mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
UI: HDS adoption replace <Modal> (#23382)
* UI: Part 1 - hds adoption replace <Modal> (#23363) * replace policy-form modal * replace clients/attribution modal * clients/config modal * scope form odal * remove button type * include toolbar to match other example templates * rotate credentials modal * add toolbar button class for hds buttons * transformation-edit modal * add back test selector * add route arg to button! * update link status * fix link-status tests * remove prevent default * update db tests * update tests * use page alert for hcp link status banner * fix scopy button selector * fix sidebar test * change to neutral banner * UI: Part 2 - hds adoption replace <Modal> (#23398) * upgrade HDS library (adds support for snippet containers * cleanup flight icons * replace transit key action modals * re-add deps as devDeps * remove line * address transit tests * UI: Part 3 - hds adoption replace <Modal> (#23415) * cleanup css * cleanup extra type attr * masked input download modal * use Hds::Button in download button" * fix size of modal * tiny icon fix * refactor download button to always render download icon * update tests * UI: Part 3.5 - hds adoption replace <Modal> (#23448) * replication-promote modal * replication component modals * replication add secondary modal * move update text for diff * UI: Part 4 - hds adoption replace <Modal> (#23451) * k8 configure modal * kv delete modal * ldap modals * pki modals * add trash icon * move deps * UI: Part 5 - hds adoption replace <Modal> (#23471) * replace confirmation modals --------- * UI: Part 6 - hds adoption replace <Modal> (#23484) * search select with modal * policy search select modal * replace date dropdown for client dashboard * change padding to top * update policy example args * lolllll test typo wow * update dropdown tests * shamir flow modals! * add one more container * update test selectors * UI: Final hds adoption replace <Modal> cleanup PR (#23522) * search select with modal * policy search select modal * replace date dropdown for client dashboard * change padding to top * update policy example args * lolllll test typo wow * update dropdown tests * shamir flow modals! * add one more container * update test selectors * remove wormhole and modal component * fix selectors * uninstall wormhole * remove shamir-modal-flow class * fix confirm modal test * fix pki and kv test * fix toolbar selector kv * client and download button test * fix-confirmation-modal-padding * fix replication modal tests so relevant modal opens (#23540) * more confirmation modal tests * adds changelog
This commit is contained in:
3
changelog/23382.txt
Normal file
3
changelog/23382.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:improvement
|
||||||
|
ui: Makes modals accessible by implementing Helios Design System modal component
|
||||||
|
```
|
||||||
@@ -73,15 +73,15 @@ export default class DatabaseConnectionEdit extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
continueWithoutRotate(evt) {
|
continueWithoutRotate() {
|
||||||
evt.preventDefault();
|
this.showSaveModal = false;
|
||||||
const { name } = this.args.model;
|
const { name } = this.args.model;
|
||||||
this.transitionToRoute(SHOW_ROUTE, name);
|
this.transitionToRoute(SHOW_ROUTE, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
continueWithRotate(evt) {
|
continueWithRotate() {
|
||||||
evt.preventDefault();
|
this.showSaveModal = false;
|
||||||
const { backend, name } = this.args.model;
|
const { backend, name } = this.args.model;
|
||||||
this.rotateCredentials(backend, name)
|
this.rotateCredentials(backend, name)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -15,10 +15,9 @@ import timestamp from 'core/utils/timestamp';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```js
|
* ```js
|
||||||
* <DateDropdown @handleSubmit={{this.actionFromParent}} @name="startTime" @submitText="Save" @handleCancel={{this.onCancel}}/>
|
* <DateDropdown @handleSubmit={{this.actionFromParent}} @name="startTime" @submitText="Save" />
|
||||||
* ```
|
* ```
|
||||||
* @param {function} handleSubmit - callback function from parent that the date picker triggers on submit
|
* @param {function} handleSubmit - callback function from parent that the date picker triggers on submit
|
||||||
* @param {function} [handleCancel] - optional callback for cancel action, if exists then buttons appear modal style with a light gray background
|
|
||||||
* @param {string} [dateType] - optional argument to give the selected month/year a type
|
* @param {string} [dateType] - optional argument to give the selected month/year a type
|
||||||
* @param {string} [submitText] - optional argument to change submit button text
|
* @param {string} [submitText] - optional argument to change submit button text
|
||||||
* @param {function} [validateDate] - parent function to validate date selection, receives date object and returns an error message that's passed to the inline alert
|
* @param {function} [validateDate] - parent function to validate date selection, receives date object and returns an error message that's passed to the inline alert
|
||||||
@@ -69,12 +68,6 @@ export default class DateDropdown extends Component {
|
|||||||
this.resetDropdown();
|
this.resetDropdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
|
||||||
handleCancel() {
|
|
||||||
this.args.handleCancel();
|
|
||||||
this.resetDropdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
resetDropdown() {
|
resetDropdown() {
|
||||||
this.maxMonthIdx = 11;
|
this.maxMonthIdx = 11;
|
||||||
this.disabledYear = null;
|
this.disabledYear = null;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
</nav>
|
</nav>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if this.showExamplePolicy}}
|
{{#if this.showExamplePolicy}}
|
||||||
<PolicyExample @policyType={{this.policy.policyType}} />
|
<PolicyExample @policyType={{this.policy.policyType}} @container="#search-select-modal" />
|
||||||
{{else}}
|
{{else}}
|
||||||
<Select
|
<Select
|
||||||
@name="policyType"
|
@name="policyType"
|
||||||
|
|||||||
@@ -23,11 +23,24 @@
|
|||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
{{#if @model.isNew}}
|
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<label class="has-text-weight-bold">Policy</label>
|
<label class="has-text-weight-bold has-right-margin-xxs">Policy</label>
|
||||||
|
{{#if @renderPolicyExampleModal}}
|
||||||
|
{{! only true in policy create and edit routes }}
|
||||||
|
<ToolbarFilters>
|
||||||
|
<Hds::Button
|
||||||
|
@text="How to write a policy"
|
||||||
|
@icon="bulb"
|
||||||
|
@size="small"
|
||||||
|
@color="tertiary"
|
||||||
|
{{on "click" (fn (mut this.showTemplateModal))}}
|
||||||
|
data-test-policy-example-button
|
||||||
|
/>
|
||||||
|
</ToolbarFilters>
|
||||||
|
{{/if}}
|
||||||
<ToolbarActions>
|
<ToolbarActions>
|
||||||
<div class="toolbar-separator"></div>
|
<div class="toolbar-separator"></div>
|
||||||
|
{{#if @model.isNew}}
|
||||||
<div class="control is-flex">
|
<div class="control is-flex">
|
||||||
<Input
|
<Input
|
||||||
id="fileUploadToggle"
|
id="fileUploadToggle"
|
||||||
@@ -40,6 +53,16 @@
|
|||||||
/>
|
/>
|
||||||
<label for="fileUploadToggle">Upload file</label>
|
<label for="fileUploadToggle">Upload file</label>
|
||||||
</div>
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{! EDITING - no file upload toggle}}
|
||||||
|
<Hds::Copy::Button
|
||||||
|
@text="Copy"
|
||||||
|
@isIconOnly={{true}}
|
||||||
|
@textToCopy={{@model.policy}}
|
||||||
|
class="transparent"
|
||||||
|
data-test-copy-button
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
</ToolbarActions>
|
</ToolbarActions>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
{{#if this.showFileUpload}}
|
{{#if this.showFileUpload}}
|
||||||
@@ -55,51 +78,10 @@
|
|||||||
data-test-policy-editor
|
data-test-policy-editor
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
|
||||||
{{! EDITING - no file upload toggle}}
|
|
||||||
<JsonEditor
|
|
||||||
@title="Policy"
|
|
||||||
@value={{@model.policy}}
|
|
||||||
@valueUpdated={{action (mut @model.policy)}}
|
|
||||||
@mode="ruby"
|
|
||||||
@extraKeys={{hash Shift-Enter=(perform this.save)}}
|
|
||||||
data-test-policy-editor
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
<div class="has-top-margin-xs">
|
<div class="has-top-margin-xs">
|
||||||
<span class="is-size-9 has-text-grey has-bottom-margin-l">
|
<span class="is-size-9 has-text-grey has-bottom-margin-l">
|
||||||
You can use Alt+Tab (Option+Tab on MacOS) in the code editor to skip to the next field.
|
You can use Alt+Tab (Option+Tab on MacOS) in the code editor to skip to the next field.
|
||||||
</span>
|
</span>
|
||||||
{{! Only renders button (and modal) if not already in the "create policy" modal }}
|
|
||||||
{{#if @renderPolicyExampleModal}}
|
|
||||||
<span class="is-size-9 has-text-grey has-bottom-margin-l">
|
|
||||||
See
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="text-button has-text-info"
|
|
||||||
{{on "click" (fn (mut this.showTemplateModal))}}
|
|
||||||
data-test-policy-example-button
|
|
||||||
>
|
|
||||||
example template
|
|
||||||
</button>.
|
|
||||||
</span>
|
|
||||||
{{! Only renders more information if already in the "create policy" modal }}
|
|
||||||
{{else}}
|
|
||||||
<p class="has-top-margin-l">
|
|
||||||
More information about
|
|
||||||
{{uppercase @model.policyType}}
|
|
||||||
policies can be found
|
|
||||||
<DocLink
|
|
||||||
@path={{if
|
|
||||||
(eq @model.policyType "acl")
|
|
||||||
"/vault/docs/concepts/policies#capabilities"
|
|
||||||
"/vault/tutorials/policies/sentinel#role-governing-policies-rgps"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
here.
|
|
||||||
</DocLink>
|
|
||||||
</p>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{#each @model.additionalAttrs as |attr|}}
|
{{#each @model.additionalAttrs as |attr|}}
|
||||||
@@ -128,26 +110,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{{! SAMPLE POLICY MODAL. Only renders modal if not already in create policy modal }}
|
|
||||||
{{#if @renderPolicyExampleModal}}
|
{{! SAMPLE POLICY MODAL. Only renders in policy create and edit routes }}
|
||||||
<Modal
|
{{#if this.showTemplateModal}}
|
||||||
@title="Example {{uppercase @model.policyType}} Policy"
|
<Hds::Modal
|
||||||
|
id="policy-example-modal"
|
||||||
|
@size="large"
|
||||||
@onClose={{fn (mut this.showTemplateModal) false}}
|
@onClose={{fn (mut this.showTemplateModal) false}}
|
||||||
@isActive={{this.showTemplateModal}}
|
|
||||||
@showCloseButton={{true}}
|
|
||||||
data-test-policy-example-modal
|
data-test-policy-example-modal
|
||||||
|
as |M|
|
||||||
>
|
>
|
||||||
<section class="modal-card-body">
|
<M.Header data-test-modal-title>
|
||||||
{{! code-mirror modifier does not render value initially until focus event fires }}
|
Example
|
||||||
{{! wait until the Modal is rendered and then show the PolicyExample (contains JsonEditor) }}
|
{{uppercase @model.policyType}}
|
||||||
{{#if this.showTemplateModal}}
|
Policy
|
||||||
<PolicyExample @policyType={{@model.policyType}} />
|
</M.Header>
|
||||||
{{/if}}
|
<M.Body>
|
||||||
</section>
|
<PolicyExample @policyType={{@model.policyType}} @container="#policy-example-modal" />
|
||||||
<div class="modal-card-head has-border-top-light">
|
</M.Body>
|
||||||
<button type="button" class="button" {{on "click" (fn (mut this.showTemplateModal) false)}} data-test-close-modal>
|
<M.Footer as |F|>
|
||||||
Close
|
<Hds::Button @text="Close" {{on "click" F.close}} data-test-modal-close-button />
|
||||||
</button>
|
</M.Footer>
|
||||||
</div>
|
</Hds::Modal>
|
||||||
</Modal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -46,7 +46,6 @@
|
|||||||
</Frame.Sidebar>
|
</Frame.Sidebar>
|
||||||
<Frame.Main id="app-main-content" class={{if this.console.isOpen "main--console-open"}}>
|
<Frame.Main id="app-main-content" class={{if this.console.isOpen "main--console-open"}}>
|
||||||
{{! outlet for app content }}
|
{{! outlet for app content }}
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<LinkStatus @status={{this.currentCluster.cluster.hcpLinkStatus}} />
|
<LinkStatus @status={{this.currentCluster.cluster.hcpLinkStatus}} />
|
||||||
{{yield}}
|
{{yield}}
|
||||||
<div data-test-console-panel class={{if this.console.isOpen "panel-open"}}>
|
<div data-test-console-panel class={{if this.console.isOpen "panel-open"}}>
|
||||||
|
|||||||
@@ -48,25 +48,19 @@
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.masked-input-toggle,
|
.button.masked-input-toggle {
|
||||||
.button.download-button {
|
|
||||||
min-width: $spacing-xl;
|
min-width: $spacing-xl;
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
color: $grey;
|
color: $grey;
|
||||||
box-shadow: 0 3px 1px 0px rgba(10, 10, 10, 0.12);
|
box-shadow: 0 3px 1px 0px rgba(10, 10, 10, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.download-button {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button.masked-input-toggle {
|
.button.masked-input-toggle {
|
||||||
border-radius: 0 $radius $radius 0;
|
border-radius: 0 $radius $radius 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.display-only {
|
.display-only {
|
||||||
.button.masked-input-toggle,
|
.button.masked-input-toggle {
|
||||||
.button.download-button {
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
height: auto;
|
height: auto;
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
align-items: center;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
display: none;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 20;
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-background {
|
|
||||||
background: $ui-gray-100;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
opacity: 0.9;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-card {
|
|
||||||
box-shadow: $box-shadow-highest;
|
|
||||||
border: 1px solid $grey-light;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
max-height: calc(100vh - 70px);
|
|
||||||
margin-top: 60px;
|
|
||||||
min-width: calc(100vw * 0.3);
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&-head {
|
|
||||||
border-radius: 0;
|
|
||||||
background-color: $grey-lightest;
|
|
||||||
border-bottom: 1px solid $grey-light;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-foot {
|
|
||||||
border-radius: 0;
|
|
||||||
border: 0;
|
|
||||||
background-color: $white;
|
|
||||||
padding: 20px;
|
|
||||||
|
|
||||||
.button:not(:last-child) {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-title.title {
|
|
||||||
margin: 0;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy-text {
|
|
||||||
background-color: $grey-lightest;
|
|
||||||
padding: $spacing-s;
|
|
||||||
margin-bottom: $spacing-s;
|
|
||||||
|
|
||||||
code {
|
|
||||||
overflow: scroll;
|
|
||||||
max-width: calc(100% - 36px);
|
|
||||||
background-color: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy-close {
|
|
||||||
margin-top: $spacing-s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-card-title.title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-card-body {
|
|
||||||
background-color: $white;
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
overflow: auto;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background-color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-highlight {
|
|
||||||
.modal-card-head {
|
|
||||||
background: $yellow-010;
|
|
||||||
border: 1px solid $yellow-100;
|
|
||||||
}
|
|
||||||
.modal-card-title {
|
|
||||||
color: $yellow-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-danger {
|
|
||||||
.modal-card-head {
|
|
||||||
background: $red-010;
|
|
||||||
border: 1px solid $red-100;
|
|
||||||
}
|
|
||||||
.modal-card-title {
|
|
||||||
color: $red-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-confirm-section {
|
|
||||||
margin: $spacing-xl 0 $spacing-m;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-card-foot-outlined {
|
|
||||||
background: $ui-gray-050;
|
|
||||||
border-top: $base-border;
|
|
||||||
}
|
|
||||||
|
|
||||||
// customize spacing (.modal-card-body is restricted to padding: 20px)
|
|
||||||
.modal-card-custom {
|
|
||||||
background-color: white;
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
&.has-padding-m {
|
|
||||||
padding: $spacing-m;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.has-padding-btm-left {
|
|
||||||
padding-bottom: $spacing-m;
|
|
||||||
padding-left: $spacing-m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// responsive css
|
|
||||||
@media screen and (min-width: 769px), print {
|
|
||||||
.modal-card,
|
|
||||||
.modal-content {
|
|
||||||
margin: 0 auto;
|
|
||||||
max-height: calc(100vh - 40px);
|
|
||||||
width: 640px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
.field-title {
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: $size-7;
|
|
||||||
}
|
|
||||||
@@ -24,29 +24,3 @@
|
|||||||
color: $black;
|
color: $black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-status {
|
|
||||||
height: 40px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
font-size: $size-7;
|
|
||||||
font-weight: $font-weight-semibold;
|
|
||||||
|
|
||||||
&.connected {
|
|
||||||
background-color: var(--token-color-surface-action);
|
|
||||||
color: var(--token-color-foreground-action-active);
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--token-color-foreground-action-active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.warning {
|
|
||||||
background-color: var(--token-color-surface-warning);
|
|
||||||
color: var(--token-color-palette-amber-300);
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--token-color-palette-amber-300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -65,6 +65,10 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
&:has(.hds-modal) {
|
||||||
|
// toolbar buttons that open/close a modal pass attrs to the modal content
|
||||||
|
white-space: wrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-filters + .toolbar-actions {
|
.toolbar-filters + .toolbar-actions {
|
||||||
|
|||||||
@@ -80,7 +80,6 @@
|
|||||||
@import './components/loader';
|
@import './components/loader';
|
||||||
@import './components/login-form';
|
@import './components/login-form';
|
||||||
@import './components/masked-input';
|
@import './components/masked-input';
|
||||||
@import './components/modal-component.scss';
|
|
||||||
@import './components/namespace-picker';
|
@import './components/namespace-picker';
|
||||||
@import './components/namespace-reminder';
|
@import './components/namespace-reminder';
|
||||||
@import './components/navigate-input';
|
@import './components/navigate-input';
|
||||||
@@ -104,7 +103,6 @@
|
|||||||
@import './components/secrets-engines-card';
|
@import './components/secrets-engines-card';
|
||||||
// action-block extends selectable-card
|
// action-block extends selectable-card
|
||||||
@import './components/action-block';
|
@import './components/action-block';
|
||||||
@import './components/shamir-modal-flow';
|
|
||||||
@import './components/shamir-progress';
|
@import './components/shamir-progress';
|
||||||
@import './components/sidebar';
|
@import './components/sidebar';
|
||||||
@import './components/splash-page';
|
@import './components/splash-page';
|
||||||
|
|||||||
@@ -91,12 +91,6 @@
|
|||||||
color: $red-500;
|
color: $red-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-warning-outlined {
|
|
||||||
background-color: $yellow-010;
|
|
||||||
border: 1px solid $yellow-700;
|
|
||||||
color: $yellow-700;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-flat {
|
&.is-flat {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -332,11 +326,11 @@ a.button.disabled {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO HDS adoption cleanup: audit styles with design and see what to keep/remove once buttons are fully HDS
|
||||||
// Existing class on <Hds::Copy::Button> component, modifying to match existing UI Structure buttons
|
// Existing class on <Hds::Copy::Button> component, modifying to match existing UI Structure buttons
|
||||||
.hds-copy-button {
|
.hds-copy-button {
|
||||||
font-weight: $font-weight-semibold;
|
font-weight: $font-weight-semibold; // TODO delete
|
||||||
box-shadow: $box-shadow-low;
|
box-shadow: $box-shadow-low; // TODO delete
|
||||||
border-radius: $radius;
|
|
||||||
|
|
||||||
&.white-icon svg {
|
&.white-icon svg {
|
||||||
color: $white;
|
color: $white;
|
||||||
@@ -350,15 +344,14 @@ a.button.disabled {
|
|||||||
color: $ui-gray-500;
|
color: $ui-gray-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-only {
|
|
||||||
margin-right: $spacing-xxs;
|
|
||||||
margin-left: $spacing-xxs;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.transparent {
|
&.transparent {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
&:hover {
|
||||||
|
border: 1px solid $grey-light;
|
||||||
|
border-color: var(--token-color-border-strong);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.primary {
|
&.primary {
|
||||||
@@ -386,3 +379,20 @@ a.button.disabled {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Existing class on <Hds::Button> component, modifying to match existing UI Structure buttons
|
||||||
|
.hds-button {
|
||||||
|
font-weight: $font-weight-semibold; // TODO consult design on font weight after button class audit
|
||||||
|
// for toolbar-button must pass arg @color="secondary"
|
||||||
|
&.toolbar-button {
|
||||||
|
color: $black;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
&:hover:not(.disabled) {
|
||||||
|
background-color: $ui-gray-100;
|
||||||
|
border: 0;
|
||||||
|
color: $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -170,3 +170,27 @@ form {
|
|||||||
label {
|
label {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HDS modifications and overrides
|
||||||
|
// * ONLY for universal changes (i.e. to address component functionality)
|
||||||
|
|
||||||
|
// <Hds::Modal>
|
||||||
|
.hds-modal {
|
||||||
|
&:has(.hds-dropdown) {
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hds-modal__body {
|
||||||
|
&:has(.hds-dropdown) {
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Hds::Dropdown>
|
||||||
|
.hds-dropdown-list-item {
|
||||||
|
> button:disabled {
|
||||||
|
color: $black;
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,14 +15,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
{{#if this.hasCsvData}}
|
{{#if this.hasCsvData}}
|
||||||
<button
|
<Hds::Button
|
||||||
data-test-attribution-export-button
|
data-test-attribution-export-button
|
||||||
type="button"
|
@text="Export attribution data"
|
||||||
class="button is-secondary"
|
@color="secondary"
|
||||||
{{on "click" (fn (mut this.showCSVDownloadModal) true)}}
|
{{on "click" (fn (mut this.showCSVDownloadModal) true)}}
|
||||||
>
|
/>
|
||||||
Export attribution data
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -91,32 +89,31 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{! MODAL FOR CSV DOWNLOAD }}
|
{{! MODAL FOR CSV DOWNLOAD }}
|
||||||
<Modal
|
{{#if this.showCSVDownloadModal}}
|
||||||
@title="Export attribution data"
|
<Hds::Modal id="attribution-csv-download-modal" @onClose={{fn (mut this.showCSVDownloadModal) false}} as |M|>
|
||||||
@type="info"
|
<M.Header @icon="info" data-test-export-modal-title>
|
||||||
@isActive={{this.showCSVDownloadModal}}
|
Export attribution data
|
||||||
@showCloseButton={{true}}
|
</M.Header>
|
||||||
@onClose={{action (mut this.showCSVDownloadModal) false}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p class="has-bottom-margin-s">
|
<p class="has-bottom-margin-s">
|
||||||
This export will include the namespace path, authentication method path, and the associated total, entity, and
|
This export will include the namespace path, authentication method path, and the associated total, entity, and
|
||||||
non-entity clients for the below
|
non-entity clients for the below
|
||||||
{{if this.formattedEndDate "date range" "month"}}.
|
{{if this.formattedEndDate "date range" "month"}}.
|
||||||
</p>
|
</p>
|
||||||
<p class="has-bottom-margin-s is-subtitle-gray">SELECTED DATE {{if this.formattedEndDate " RANGE"}}</p>
|
<p class="has-bottom-margin-s is-subtitle-gray">SELECTED DATE {{if this.formattedEndDate " RANGE"}}</p>
|
||||||
<p class="has-bottom-margin-s">{{this.formattedStartDate}} {{if this.formattedEndDate "-"}} {{this.formattedEndDate}}</p>
|
<p class="has-bottom-margin-s" data-test-export-date-range>
|
||||||
</section>
|
{{this.formattedStartDate}}
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
{{if this.formattedEndDate "-"}}
|
||||||
<button type="button" class="button is-primary" {{on "click" (fn this.exportChartData this.formattedCsvFileName)}}>
|
{{this.formattedEndDate}}</p>
|
||||||
Export
|
</M.Body>
|
||||||
</button>
|
<M.Footer as |F|>
|
||||||
<button type="button" class="button is-secondary" onclick={{action (mut this.showCSVDownloadModal) false}}>
|
<Hds::ButtonSet>
|
||||||
Cancel
|
<Hds::Button @text="Export" {{on "click" (fn this.exportChartData this.formattedCsvFileName)}} />
|
||||||
</button>
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} />
|
||||||
|
</Hds::ButtonSet>
|
||||||
{{#if @upgradeExplanation}}
|
{{#if @upgradeExplanation}}
|
||||||
<div class="has-text-grey is-size-8">
|
<div class="has-text-grey is-size-8 has-top-padding-m">
|
||||||
<AlertInline @type="warning" @isMarginless={{true}}>
|
<AlertInline @type="warning">
|
||||||
Your data contains an upgrade.
|
Your data contains an upgrade.
|
||||||
<DocLink
|
<DocLink
|
||||||
@path="/vault/docs/concepts/client-count/faq#q-which-vault-version-reflects-the-most-accurate-client-counts"
|
@path="/vault/docs/concepts/client-count/faq#q-which-vault-version-reflects-the-most-accurate-client-counts"
|
||||||
@@ -127,5 +124,6 @@
|
|||||||
<p class="has-left-padding-l">{{@upgradeExplanation}}</p>
|
<p class="has-left-padding-l">{{@upgradeExplanation}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</footer>
|
</M.Footer>
|
||||||
</Modal>
|
</Hds::Modal>
|
||||||
|
{{/if}}
|
||||||
@@ -47,19 +47,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<Modal
|
{{#if this.modalOpen}}
|
||||||
@title={{this.modalTitle}}
|
<Hds::Modal id="clients-config-modal" @color="warning" @onClose={{fn (mut this.modalOpen) false}} as |M|>
|
||||||
@onClose={{action (mut this.modalOpen) false}}
|
<M.Header @icon="alert-triangle" data-test-clients-config-modal="title">
|
||||||
@isActive={{this.modalOpen}}
|
{{this.modalTitle}}
|
||||||
@type="warning"
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
{{#if (eq @model.enabled "On")}}
|
{{#if (eq @model.enabled "On")}}
|
||||||
<p class="has-bottom-margin-s" data-test-clients-config-modal="on">
|
<p class="has-bottom-margin-s" data-test-clients-config-modal="on">
|
||||||
Vault will start tracking data starting from today’s date,
|
Vault will start tracking data starting from today’s date,
|
||||||
{{date-format (now) "MMMM d, yyyy"}}. If you’ve previously enabled usage tracking, that historical data will still
|
{{date-format (now) "MMMM d, yyyy"}}. If you’ve previously enabled usage tracking, that historical data will
|
||||||
be available to you.
|
still be available to you.
|
||||||
</p>
|
</p>
|
||||||
{{else}}
|
{{else}}
|
||||||
<p class="has-bottom-margin-s" data-test-clients-config-modal="off">
|
<p class="has-bottom-margin-s" data-test-clients-config-modal="off">
|
||||||
@@ -68,26 +66,15 @@
|
|||||||
</p>
|
</p>
|
||||||
<p>Are you sure?</p>
|
<p>Are you sure?</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
type="button"
|
<Hds::Button @text="Continue" {{on "click" (perform this.save)}} data-test-clients-config-modal="continue" />
|
||||||
class="button is-primary"
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} data-test-clients-config-modal="cancel" />
|
||||||
data-test-clients-config-modal="continue"
|
</Hds::ButtonSet>
|
||||||
{{on "click" (perform this.save)}}
|
</M.Footer>
|
||||||
>
|
</Hds::Modal>
|
||||||
Continue
|
{{/if}}
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="button is-secondary"
|
|
||||||
{{on "click" (fn (mut this.modalOpen) false)}}
|
|
||||||
data-test-clients-config-modal="cancel"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless" data-test-clients-config-table>
|
<div class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless" data-test-clients-config-table>
|
||||||
{{#each this.infoRows as |item|}}
|
{{#each this.infoRows as |item|}}
|
||||||
|
|||||||
@@ -175,26 +175,28 @@
|
|||||||
</EmptyState>
|
</EmptyState>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{! BILLING START DATE MODAL }}
|
{{! BILLING START DATE MODAL }}
|
||||||
|
{{#if this.showBillingStartModal}}
|
||||||
<Modal
|
<Hds::Modal id="clients-edit-date-modal" @onClose={{fn (mut this.showBillingStartModal) false}} as |M|>
|
||||||
@title="Edit start month"
|
<M.Header>
|
||||||
@onClose={{action (mut this.showBillingStartModal) false}}
|
Edit start month
|
||||||
@isActive={{this.showBillingStartModal}}
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-custom has-padding-m">
|
|
||||||
<p class="has-bottom-margin-s">
|
<p class="has-bottom-margin-s">
|
||||||
{{this.versionText.description}}
|
{{this.versionText.description}}
|
||||||
</p>
|
</p>
|
||||||
<p><strong>{{this.versionText.label}}</strong></p>
|
<p><strong>{{this.versionText.label}}</strong></p>
|
||||||
</section>
|
|
||||||
<DateDropdown
|
<DateDropdown
|
||||||
|
class="has-top-padding-s"
|
||||||
@handleSubmit={{this.handleClientActivityQuery}}
|
@handleSubmit={{this.handleClientActivityQuery}}
|
||||||
@dateType="startDate"
|
@dateType="startDate"
|
||||||
@submitText="Save"
|
@submitText="Save"
|
||||||
@handleCancel={{fn this.handleClientActivityQuery (hash dateType="cancel")}}
|
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</M.Body>
|
||||||
</div>
|
<M.Footer as |F|>
|
||||||
|
<Hds::Button data-test-date-dropdown-cancel @text="Cancel" @color="secondary" {{on "click" F.close}} />
|
||||||
|
</M.Footer>
|
||||||
|
</Hds::Modal>
|
||||||
|
{{/if}}
|
||||||
@@ -352,35 +352,32 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<Modal
|
{{#if this.showSaveModal}}
|
||||||
@title="Rotate your root credentials?"
|
<Hds::Modal id="rotate-credentials-modal" @onClose={{this.continueWithoutRotate}} as |M|>
|
||||||
@onClose={{this.continueWithoutRotate}}
|
<M.Header @icon="info" data-test-db-connection-modal-title>
|
||||||
@isActive={{this.showSaveModal}}
|
Rotate your root credentials?
|
||||||
@type="info"
|
</M.Header>
|
||||||
@showCloseButton={{false}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p class="has-bottom-margin-s">
|
<p class="has-bottom-margin-s">
|
||||||
It’s best practice to rotate the root credential immediately after the initial configuration of each database. Once
|
It’s best practice to rotate the root credential immediately after the initial configuration of each database. Once
|
||||||
rotated,
|
rotated,
|
||||||
<strong>only Vault knows the new root password</strong>.
|
<strong>only Vault knows the new root password</strong>.
|
||||||
</p>
|
</p>
|
||||||
<p>Would you like to rotate your new credentials? You can also do this later.</p>
|
<p>Would you like to rotate your new credentials? You can also do this later.</p>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
type="button"
|
<Hds::Button @text="Rotate and enable" {{on "click" this.continueWithRotate}} data-test-enable-rotate-connection />
|
||||||
class="button is-primary"
|
<Hds::Button
|
||||||
{{on "click" this.continueWithRotate}}
|
@text="Enable without rotating"
|
||||||
data-test-enable-rotate-connection
|
@color="secondary"
|
||||||
>
|
{{on "click" this.continueWithoutRotate}}
|
||||||
Rotate and enable
|
data-test-enable-connection
|
||||||
</button>
|
/>
|
||||||
<button type="button" class="button is-secondary" {{on "click" this.continueWithoutRotate}} data-test-enable-connection>
|
</Hds::ButtonSet>
|
||||||
Enable without rotating
|
</M.Footer>
|
||||||
</button>
|
</Hds::Modal>
|
||||||
</footer>
|
{{/if}}
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
@title="Delete connection?"
|
@title="Delete connection?"
|
||||||
|
|||||||
@@ -3,89 +3,36 @@
|
|||||||
SPDX-License-Identifier: BUSL-1.1
|
SPDX-License-Identifier: BUSL-1.1
|
||||||
~}}
|
~}}
|
||||||
|
|
||||||
<div class="modal-card-custom has-padding-btm-left">
|
<Hds::SegmentedGroup ...attributes as |S|>
|
||||||
<BasicDropdown @class="popup-menu" @horizontalPosition="auto-right" @verticalPosition="below" as |D|>
|
<S.Dropdown @height="200px" as |dd|>
|
||||||
<D.Trigger
|
<dd.ToggleButton data-test-toggle-month @text={{or this.selectedMonth.name "Month"}} @color="secondary" />
|
||||||
data-test-popup-menu-trigger="month"
|
|
||||||
class={{concat "toolbar-link" (if D.isOpen " is-active")}}
|
|
||||||
@htmlTag="button"
|
|
||||||
>
|
|
||||||
{{or this.selectedMonth.name "Month"}}
|
|
||||||
<Chevron @direction="down" @isButton={{true}} />
|
|
||||||
</D.Trigger>
|
|
||||||
<D.Content @defaultClass="popup-menu-content is-wide">
|
|
||||||
<nav class="box menu scroll" aria-label="months">
|
|
||||||
<ul data-test-month-list class="menu-list">
|
|
||||||
{{#each this.dropdownMonths as |month|}}
|
{{#each this.dropdownMonths as |month|}}
|
||||||
<button
|
<dd.Interactive
|
||||||
data-test-dropdown-month={{month.name}}
|
data-test-dropdown-month={{month.name}}
|
||||||
type="button"
|
|
||||||
class="button link"
|
|
||||||
disabled={{if (gt month.index this.maxMonthIdx) true false}}
|
disabled={{if (gt month.index this.maxMonthIdx) true false}}
|
||||||
{{on "click" (fn this.selectMonth month D.actions)}}
|
{{on "click" (fn this.selectMonth month dd)}}
|
||||||
>
|
@text={{month.name}}
|
||||||
{{month.name}}
|
/>
|
||||||
</button>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</S.Dropdown>
|
||||||
</nav>
|
<S.Dropdown data-test-year-list @height="200px" as |dd|>
|
||||||
</D.Content>
|
<dd.ToggleButton data-test-toggle-year @text={{or this.selectedYear "Year"}} @color="secondary" />
|
||||||
</BasicDropdown>
|
|
||||||
<BasicDropdown @class="popup-menu" @horizontalPosition="auto-right" @verticalPosition="below" as |D|>
|
|
||||||
<D.Trigger
|
|
||||||
data-test-popup-menu-trigger="year"
|
|
||||||
class={{concat "toolbar-link" (if D.isOpen " is-active")}}
|
|
||||||
@htmlTag="button"
|
|
||||||
>
|
|
||||||
{{or this.selectedYear "Year"}}
|
|
||||||
<Chevron @direction="down" @isButton={{true}} />
|
|
||||||
</D.Trigger>
|
|
||||||
<D.Content @defaultClass="popup-menu-content is-wide">
|
|
||||||
<nav class="box menu" aria-label="years">
|
|
||||||
<ul data-test-year-list class="menu-list">
|
|
||||||
{{#each this.dropdownYears as |year|}}
|
{{#each this.dropdownYears as |year|}}
|
||||||
<button
|
<dd.Interactive
|
||||||
data-test-dropdown-year={{year}}
|
data-test-dropdown-year={{year}}
|
||||||
type="button"
|
|
||||||
class="button link"
|
|
||||||
disabled={{if (eq year this.disabledYear) true false}}
|
disabled={{if (eq year this.disabledYear) true false}}
|
||||||
{{on "click" (fn this.selectYear year D.actions)}}
|
{{on "click" (fn this.selectYear year dd)}}
|
||||||
>
|
@text={{year}}
|
||||||
{{year}}
|
/>
|
||||||
</button>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</S.Dropdown>
|
||||||
</nav>
|
<S.Button
|
||||||
</D.Content>
|
|
||||||
</BasicDropdown>
|
|
||||||
{{#unless @handleCancel}}
|
|
||||||
<button
|
|
||||||
data-test-date-dropdown-submit
|
data-test-date-dropdown-submit
|
||||||
type="button"
|
|
||||||
class="button is-primary"
|
|
||||||
disabled={{if (and this.selectedMonth this.selectedYear) false true}}
|
disabled={{if (and this.selectedMonth this.selectedYear) false true}}
|
||||||
{{on "click" this.handleSubmit}}
|
{{on "click" this.handleSubmit}}
|
||||||
>
|
@text={{or @submitText "Submit"}}
|
||||||
{{or @submitText "Submit"}}
|
/>
|
||||||
</button>
|
</Hds::SegmentedGroup>
|
||||||
{{/unless}}
|
{{#if this.invalidDate}}
|
||||||
{{#if this.invalidDate}}
|
|
||||||
<AlertInline @type="danger" @message={{this.invalidDate}} @paddingTop={{true}} @mimicRefresh={{true}} />
|
<AlertInline @type="danger" @message={{this.invalidDate}} @paddingTop={{true}} @mimicRefresh={{true}} />
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{#if @handleCancel}}
|
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
|
||||||
<button
|
|
||||||
data-test-date-dropdown-submit
|
|
||||||
type="button"
|
|
||||||
class="button is-primary"
|
|
||||||
disabled={{if (and this.selectedMonth this.selectedYear) false true}}
|
|
||||||
{{on "click" this.handleSubmit}}
|
|
||||||
>
|
|
||||||
{{or @submitText "Submit"}}
|
|
||||||
</button>
|
|
||||||
<button data-test-date-dropdown-cancel type="button" class="button is-secondary" {{on "click" this.handleCancel}}>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -4,9 +4,8 @@
|
|||||||
~}}
|
~}}
|
||||||
|
|
||||||
{{#if (and this.state this.version.isEnterprise)}}
|
{{#if (and this.state this.version.isEnterprise)}}
|
||||||
<div class="link-status {{if (eq this.state 'connected') 'connected' 'warning'}}">
|
<Hds::Alert @type="page" @color={{if (eq this.state "connected") "neutral" "warning"}} as |A|>
|
||||||
<Icon @name="info" />
|
<A.Title data-test-link-status>
|
||||||
<p data-test-link-status>
|
|
||||||
{{#if (eq this.state "connected")}}
|
{{#if (eq this.state "connected")}}
|
||||||
This self-managed Vault is linked to
|
This self-managed Vault is linked to
|
||||||
<ExternalLink @href="https://portal.cloud.hashicorp.com/sign-in">
|
<ExternalLink @href="https://portal.cloud.hashicorp.com/sign-in">
|
||||||
@@ -19,18 +18,16 @@
|
|||||||
</button>
|
</button>
|
||||||
for more information.
|
for more information.
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</p>
|
</A.Title>
|
||||||
</div>
|
</Hds::Alert>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<Modal
|
{{#if this.showModal}}
|
||||||
@title="HCP Link error"
|
<Hds::Modal id="hcp-link-error-modal" @color="warning" @size="small" @onClose={{fn (mut this.showModal) false}} as |M|>
|
||||||
@onClose={{fn (mut this.showModal) false}}
|
<M.Header @icon="alert-triangle">
|
||||||
@isActive={{this.showModal}}
|
HCP Link error
|
||||||
@type="info"
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<div>
|
<div>
|
||||||
<p class="has-text-weight-bold">Timestamp</p>
|
<p class="has-text-weight-bold">Timestamp</p>
|
||||||
<p data-test-link-status-timestamp>
|
<p data-test-link-status-timestamp>
|
||||||
@@ -53,15 +50,9 @@
|
|||||||
<p class="has-text-weight-bold">Additional information</p>
|
<p class="has-text-weight-bold">Additional information</p>
|
||||||
<p>Check the logs for more information</p>
|
<p>Check the logs for more information</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button
|
<Hds::Button @text="Close" {{on "click" F.close}} data-test-link-status-close />
|
||||||
type="button"
|
</M.Footer>
|
||||||
class="button is-primary"
|
</Hds::Modal>
|
||||||
{{on "click" (fn (mut this.showModal) false)}}
|
{{/if}}
|
||||||
data-test-link-status-close
|
|
||||||
>
|
|
||||||
Close
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
@id="entities"
|
@id="entities"
|
||||||
@label="Entities"
|
@label="Entities"
|
||||||
@placeholder="Search"
|
@placeholder="Search"
|
||||||
|
@renderInPlace={{true}}
|
||||||
@models={{array "identity/entity"}}
|
@models={{array "identity/entity"}}
|
||||||
@inputValue={{@model.entityIds}}
|
@inputValue={{@model.entityIds}}
|
||||||
@shouldRenderName={{true}}
|
@shouldRenderName={{true}}
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
@id="groups"
|
@id="groups"
|
||||||
@label="Groups"
|
@label="Groups"
|
||||||
@placeholder="Search"
|
@placeholder="Search"
|
||||||
|
@renderInPlace={{true}}
|
||||||
@models={{array "identity/group"}}
|
@models={{array "identity/group"}}
|
||||||
@inputValue={{@model.groupIds}}
|
@inputValue={{@model.groupIds}}
|
||||||
@shouldRenderName={{true}}
|
@shouldRenderName={{true}}
|
||||||
|
|||||||
@@ -29,6 +29,15 @@
|
|||||||
Scope
|
Scope
|
||||||
</h1>
|
</h1>
|
||||||
</p.levelLeft>
|
</p.levelLeft>
|
||||||
|
<p.levelRight>
|
||||||
|
<Hds::Button
|
||||||
|
@text="How to write JSON template for scopes"
|
||||||
|
@icon="bulb"
|
||||||
|
@color="tertiary"
|
||||||
|
{{on "click" (fn (mut this.showTemplateModal))}}
|
||||||
|
data-test-oidc-scope-example
|
||||||
|
/>
|
||||||
|
</p.levelRight>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<form {{on "submit" (perform this.save)}}>
|
<form {{on "submit" (perform this.save)}}>
|
||||||
@@ -41,15 +50,8 @@
|
|||||||
<FormField @attr={{field}} @model={{@model}} @modelValidations={{this.modelValidations}} />
|
<FormField @attr={{field}} @model={{@model}} @modelValidations={{this.modelValidations}} />
|
||||||
{{/each}}
|
{{/each}}
|
||||||
<p class="is-size-9 has-text-grey has-bottom-margin-l">
|
<p class="is-size-9 has-text-grey has-bottom-margin-l">
|
||||||
You can use Alt+Tab (Option+Tab on MacOS) in the code editor to skip to the next field. See
|
You can use Alt+Tab (Option+Tab on MacOS) in the code editor to skip to the next field. Click 'How to write JSON
|
||||||
<button
|
template for scopes' to view an example.
|
||||||
type="button"
|
|
||||||
class="text-button has-text-info"
|
|
||||||
{{on "click" (fn (mut this.showTemplateModal))}}
|
|
||||||
data-test-oidc-scope-example
|
|
||||||
>
|
|
||||||
example template
|
|
||||||
</button>.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="has-top-margin-l has-bottom-margin-l">
|
<div class="has-top-margin-l has-bottom-margin-l">
|
||||||
@@ -78,40 +80,25 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<Modal
|
{{#if this.showTemplateModal}}
|
||||||
@title="Scope template"
|
<Hds::Modal id="scope-template-modal" @size="large" @onClose={{fn (mut this.showTemplateModal) false}} as |M|>
|
||||||
@onClose={{fn (mut this.showTemplateModal) false}}
|
<M.Header data-test-scope-modal="title">
|
||||||
@isActive={{this.showTemplateModal}}
|
Scope template
|
||||||
@showCloseButton={{true}}
|
</M.Header>
|
||||||
>
|
<M.Body>
|
||||||
<section class="modal-card-body">
|
<p data-test-scope-modal="text">
|
||||||
<div class="is-flex-between is-flex-center has-bottom-margin-s">
|
|
||||||
<p data-test-modal-text>
|
|
||||||
Example of a JSON template for scopes:
|
Example of a JSON template for scopes:
|
||||||
</p>
|
</p>
|
||||||
<Hds::Copy::Button
|
<JsonEditor @value={{this.exampleTemplate}} @mode="ruby" @readOnly={{true}} @container=".hds-modal" />
|
||||||
@text="Copy"
|
|
||||||
@isIconOnly={{true}}
|
|
||||||
@textToCopy={{this.exampleTemplate}}
|
|
||||||
class="transparent"
|
|
||||||
data-test-copy-button
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{{! code-mirror modifier does not render value initially in wormhole until focus event fires }}
|
|
||||||
{{! wait until the Modal is rendered and then show the JsonEditor }}
|
|
||||||
{{#if this.showTemplateModal}}
|
|
||||||
<JsonEditor @value={{this.exampleTemplate}} @mode="ruby" @readOnly={{true}} @showToolbar={{false}} />
|
|
||||||
{{/if}}
|
|
||||||
<p class="has-top-margin-m">
|
<p class="has-top-margin-m">
|
||||||
The full list of template parameters can be found
|
The full list of template parameters can be found
|
||||||
<DocLink @path="/vault/docs/concepts/oidc-provider#scopes">
|
<DocLink @path="/vault/docs/concepts/oidc-provider#scopes">
|
||||||
here.
|
here.
|
||||||
</DocLink>
|
</DocLink>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</M.Body>
|
||||||
<div class="modal-card-head has-border-top-light">
|
<M.Footer as |F|>
|
||||||
<button type="button" class="button" {{on "click" (fn (mut this.showTemplateModal) false)}} data-test-close-modal>
|
<Hds::Button @text="Close" {{on "click" F.close}} data-test-close-modal />
|
||||||
Close
|
</M.Footer>
|
||||||
</button>
|
</Hds::Modal>
|
||||||
</div>
|
{{/if}}
|
||||||
</Modal>
|
|
||||||
@@ -53,14 +53,13 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if this.capabilities.canUpdate}}
|
{{#if this.capabilities.canUpdate}}
|
||||||
{{#if (gt this.model.allowed_roles.length 0)}}
|
{{#if (gt this.model.allowed_roles.length 0)}}
|
||||||
<button
|
<Hds::Button
|
||||||
class="toolbar-link"
|
@text="Edit transformation"
|
||||||
onclick={{action (mut this.isEditModalActive) true}}
|
@color="secondary"
|
||||||
type="button"
|
class="toolbar-button"
|
||||||
|
{{on "click" (fn (mut this.isEditModalActive) true)}}
|
||||||
data-test-edit-link
|
data-test-edit-link
|
||||||
>
|
/>
|
||||||
Edit transformation
|
|
||||||
</button>
|
|
||||||
{{else}}
|
{{else}}
|
||||||
<ToolbarSecretLink @secret={{this.model.id}} @mode="edit" data-test-edit-link={{true}} @replace={{true}}>
|
<ToolbarSecretLink @secret={{this.model.id}} @mode="edit" data-test-edit-link={{true}} @replace={{true}}>
|
||||||
Edit transformation
|
Edit transformation
|
||||||
@@ -96,30 +95,27 @@
|
|||||||
<MessageError @model={{this.model}} @errorMessage={{this.error}} />
|
<MessageError @model={{this.model}} @errorMessage={{this.error}} />
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
|
|
||||||
<Modal
|
{{#if this.isEditModalActive}}
|
||||||
@title="Edit transformation"
|
<Hds::Modal id="transformation-edit-modal" @color="warning" @onClose={{fn (mut this.isEditModalActive) false}} as |M|>
|
||||||
@onClose={{action (mut this.isEditModalActive) false}}
|
<M.Header @icon="alert-triangle">
|
||||||
@isActive={{this.isEditModalActive}}
|
Edit transformation
|
||||||
@type="warning"
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p>
|
<p>
|
||||||
You’re editing a transformation that is in use by at least one role. Editing it may mean that encode and decode
|
You’re editing a transformation that is in use by at least one role. Editing it may mean that encode and decode
|
||||||
operations stop working. Are you sure?
|
operations stop working. Are you sure?
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<LinkTo
|
<Hds::ButtonSet>
|
||||||
|
<Hds::Button
|
||||||
|
@text="Confirm"
|
||||||
@route="vault.cluster.secrets.backend.edit"
|
@route="vault.cluster.secrets.backend.edit"
|
||||||
@model={{this.model.id}}
|
@model={{this.model.id}}
|
||||||
class="button is-primary"
|
data-test-edit-confirm-button
|
||||||
data-test-edit-confirm-button={{true}}
|
/>
|
||||||
>
|
<Hds::Button @color="secondary" @text="Cancel" {{on "click" F.close}} />
|
||||||
Confirm
|
</Hds::ButtonSet>
|
||||||
</LinkTo>
|
</M.Footer>
|
||||||
<button type="button" class="button is-secondary" onclick={{action (mut this.isEditModalActive) false}}>
|
</Hds::Modal>
|
||||||
Cancel
|
{{/if}}
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
@@ -74,19 +74,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<Modal @title="Copy your generated key" @onClose={{action (mut @isModalActive) false}} @isActive={{@isModalActive}}>
|
{{#if @isModalActive}}
|
||||||
<section class="modal-card-body">
|
<Hds::Modal id="transit-datakey-modal" @onClose={{fn (mut @isModalActive) false}} as |M|>
|
||||||
<div class="box is-shadowless is-fullwidth is-sideless">
|
<M.Header>
|
||||||
|
Copy your generated key
|
||||||
|
</M.Header>
|
||||||
|
<M.Body>
|
||||||
{{#if (eq @param "plaintext")}}
|
{{#if (eq @param "plaintext")}}
|
||||||
<h2 class="has-text-weight-semibold is-6">Plaintext</h2>
|
<h2 class="has-text-weight-semibold is-6">Plaintext</h2>
|
||||||
<p class="sub-text">Plaintext is base64 encoded</p>
|
<p class="sub-text">Plaintext is base64 encoded</p>
|
||||||
<Hds::Copy::Snippet class="has-bottom-margin-m" @textToCopy={{@plaintext}} @color="secondary" />
|
<Hds::Copy::Snippet
|
||||||
|
class="has-bottom-margin-m"
|
||||||
|
@textToCopy={{@plaintext}}
|
||||||
|
@color="secondary"
|
||||||
|
@container="#transit-datakey-modal"
|
||||||
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<h2 class="has-text-weight-semibold is-6">Ciphertext</h2>
|
<h2 class="has-text-weight-semibold is-6">Ciphertext</h2>
|
||||||
<Hds::Copy::Snippet @textToCopy={{@ciphertext}} @color="secondary" />
|
<Hds::Copy::Snippet @textToCopy={{@ciphertext}} @color="secondary" @container="#transit-datakey-modal" />
|
||||||
</div>
|
</M.Body>
|
||||||
</section>
|
<M.Footer as |F|>
|
||||||
<footer class="modal-card-foot">
|
<Hds::Button @text="Close" {{on "click" F.close}} />
|
||||||
<button type="button" class="button is-primary" {{on "click" (fn (mut @isModalActive) false)}}>Close</button>
|
</M.Footer>
|
||||||
</footer>
|
</Hds::Modal>
|
||||||
</Modal>
|
{{/if}}
|
||||||
@@ -56,16 +56,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{{#if @isModalActive}}
|
{{#if @isModalActive}}
|
||||||
<Modal @title="Copy your unwrapped data" @onClose={{action (mut @isModalActive) false}} @isActive={{@isModalActive}}>
|
<Hds::Modal id="transit-decrypt-modal" @onClose={{fn (mut @isModalActive) false}} data-test-decrypt-modal as |M|>
|
||||||
<section class="modal-card-body">
|
<M.Header>
|
||||||
<div class="box is-shadowless is-fullwidth is-sideless">
|
Copy your unwrapped data
|
||||||
|
</M.Header>
|
||||||
|
<M.Body>
|
||||||
<h2 class="has-text-weight-semibold is-6">Plaintext</h2>
|
<h2 class="has-text-weight-semibold is-6">Plaintext</h2>
|
||||||
<p class="sub-text">Plaintext is base64 encoded</p>
|
<p class="sub-text">Plaintext is base64 encoded</p>
|
||||||
<Hds::Copy::Snippet @textToCopy={{@plaintext}} @color="secondary" data-test-encrypted-value="plaintext" />
|
<Hds::Copy::Snippet
|
||||||
</div>
|
@textToCopy={{@plaintext}}
|
||||||
</section>
|
@color="secondary"
|
||||||
<footer class="modal-card-foot">
|
@container="#transit-decrypt-modal"
|
||||||
<button type="button" class="button is-primary" {{on "click" (fn (mut @isModalActive) false)}}>Close</button>
|
data-test-encrypted-value="plaintext"
|
||||||
</footer>
|
/>
|
||||||
</Modal>
|
</M.Body>
|
||||||
|
<M.Footer as |F|>
|
||||||
|
<Hds::Button @text="Close" {{on "click" F.close}} />
|
||||||
|
</M.Footer>
|
||||||
|
</Hds::Modal>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -69,19 +69,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<Modal
|
{{#if @isModalActive}}
|
||||||
@title="Copy your token"
|
<Hds::Modal id="transit-encrypt-modal" @onClose={{fn (mut @isModalActive) false}} data-test-encrypt-modal as |M|>
|
||||||
@onClose={{action (mut @isModalActive) false}}
|
<M.Header>
|
||||||
@isActive={{@isModalActive}}
|
Copy your token
|
||||||
data-test-encrypt-modal
|
</M.Header>
|
||||||
>
|
<M.Body>
|
||||||
<section class="modal-card-body">
|
|
||||||
<div class="box is-shadowless is-fullwidth is-sideless">
|
|
||||||
<h2 class="title is-6">Ciphertext</h2>
|
<h2 class="title is-6">Ciphertext</h2>
|
||||||
<Hds::Copy::Snippet @textToCopy={{@ciphertext}} @color="secondary" data-test-encrypted-value="ciphertext" />
|
<Hds::Copy::Snippet
|
||||||
</div>
|
@textToCopy={{@ciphertext}}
|
||||||
</section>
|
@color="secondary"
|
||||||
<footer class="modal-card-foot">
|
@container="#transit-encrypt-modal"
|
||||||
<button type="button" class="button is-primary" {{on "click" (fn (mut @isModalActive) false)}}>Close</button>
|
data-test-encrypted-value="ciphertext"
|
||||||
</footer>
|
/>
|
||||||
</Modal>
|
</M.Body>
|
||||||
|
<M.Footer as |F|>
|
||||||
|
<Hds::Button @text="Close" {{on "click" F.close}} />
|
||||||
|
</M.Footer>
|
||||||
|
</Hds::Modal>
|
||||||
|
{{/if}}
|
||||||
@@ -65,15 +65,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<Modal @title="Copy your wrapped key" @onClose={{action (mut @isModalActive) false}} @isActive={{@isModalActive}}>
|
{{#if @isModalActive}}
|
||||||
<section class="modal-card-body">
|
<Hds::Modal id="transit-export-modal" @onClose={{fn (mut @isModalActive) false}} as |M|>
|
||||||
<div class="box is-shadowless is-fullwidth is-sideless">
|
<M.Header>
|
||||||
<h2 class="title is-6">Wrapped Key</h2>
|
Copy your wrapped key
|
||||||
|
</M.Header>
|
||||||
|
<M.Body>
|
||||||
|
<h2 class="title is-6">Wrapped key</h2>
|
||||||
{{#if this.wrapTTL}}
|
{{#if this.wrapTTL}}
|
||||||
<Hds::Copy::Snippet
|
<Hds::Copy::Snippet
|
||||||
class="has-bottom-margin-m"
|
class="has-bottom-margin-m"
|
||||||
@textToCopy={{@wrappedToken}}
|
@textToCopy={{@wrappedToken}}
|
||||||
@color="secondary"
|
@color="secondary"
|
||||||
|
@container="#transit-export-modal"
|
||||||
data-test-encrypted-value="export"
|
data-test-encrypted-value="export"
|
||||||
/>
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
@@ -85,13 +89,14 @@
|
|||||||
@text="Copy"
|
@text="Copy"
|
||||||
@isIconOnly={{true}}
|
@isIconOnly={{true}}
|
||||||
@textToCopy={{stringify @keys}}
|
@textToCopy={{stringify @keys}}
|
||||||
|
@container="#transit-export-modal"
|
||||||
class="transparent top-right-absolute"
|
class="transparent top-right-absolute"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</M.Body>
|
||||||
</section>
|
<M.Footer as |F|>
|
||||||
<footer class="modal-card-foot">
|
<Hds::Button @text="Close" {{on "click" F.close}} />
|
||||||
<button type="button" class="button is-primary" {{on "click" (fn (mut @isModalActive) false)}}>Close</button>
|
</M.Footer>
|
||||||
</footer>
|
</Hds::Modal>
|
||||||
</Modal>
|
{{/if}}
|
||||||
@@ -51,14 +51,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<Modal @title="Copy your unwrapped data" @onClose={{action (mut @isModalActive) false}} @isActive={{@isModalActive}}>
|
{{#if @isModalActive}}
|
||||||
<section class="modal-card-body">
|
<Hds::Modal id="transit-hmac-modal" @onClose={{fn (mut @isModalActive) false}} as |M|>
|
||||||
<div class="box is-shadowless is-fullwidth is-sideless">
|
<M.Header>
|
||||||
|
Copy your unwrapped data
|
||||||
|
</M.Header>
|
||||||
|
<M.Body>
|
||||||
<h2 class="title is-6">HMAC</h2>
|
<h2 class="title is-6">HMAC</h2>
|
||||||
<Hds::Copy::Snippet @textToCopy={{@hmac}} @color="secondary" data-test-encrypted-value="hmac" />
|
<Hds::Copy::Snippet
|
||||||
</div>
|
@textToCopy={{@hmac}}
|
||||||
</section>
|
@color="secondary"
|
||||||
<footer class="modal-card-foot">
|
@container="#transit-hmac-modal"
|
||||||
<button type="button" class="button is-primary" {{on "click" (fn (mut @isModalActive) false)}}>Close</button>
|
data-test-encrypted-value="hmac"
|
||||||
</footer>
|
/>
|
||||||
</Modal>
|
</M.Body>
|
||||||
|
<M.Footer as |F|>
|
||||||
|
<Hds::Button @text="Close" {{on "click" F.close}} />
|
||||||
|
</M.Footer>
|
||||||
|
</Hds::Modal>
|
||||||
|
{{/if}}
|
||||||
@@ -63,14 +63,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<Modal @title="Copy your token" @onClose={{action (mut @isModalActive)}} @isActive={{@isModalActive}}>
|
{{#if @isModalActive}}
|
||||||
<section class="modal-card-body">
|
<Hds::Modal id="transit-rewrap-modal" @onClose={{fn (mut @isModalActive) false}} as |M|>
|
||||||
<div class="box is-shadowless is-fullwidth is-sideless">
|
<M.Header>
|
||||||
|
Copy your token
|
||||||
|
</M.Header>
|
||||||
|
<M.Body>
|
||||||
<h2 class="title is-6">Ciphertext</h2>
|
<h2 class="title is-6">Ciphertext</h2>
|
||||||
<Hds::Copy::Snippet @textToCopy={{@ciphertext}} @color="secondary" />
|
<Hds::Copy::Snippet @textToCopy={{@ciphertext}} @color="secondary" @container="#transit-rewrap-modal" />
|
||||||
</div>
|
</M.Body>
|
||||||
</section>
|
<M.Footer as |F|>
|
||||||
<footer class="modal-card-foot">
|
<Hds::Button @text="Close" {{on "click" F.close}} />
|
||||||
<button type="button" class="button is-primary" {{on "click" (fn (mut @isModalActive) false)}}>Close</button>
|
</M.Footer>
|
||||||
</footer>
|
</Hds::Modal>
|
||||||
</Modal>
|
{{/if}}
|
||||||
@@ -120,19 +120,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<Modal
|
{{#if @isModalActive}}
|
||||||
@title="Copy your signature"
|
<Hds::Modal id="transit-sign-modal" @onClose={{fn (mut @isModalActive) false}} data-test-sign-modal as |M|>
|
||||||
@onClose={{action (mut @isModalActive) false}}
|
<M.Header>
|
||||||
@isActive={{@isModalActive}}
|
Copy your signature
|
||||||
data-test-sign-modal
|
</M.Header>
|
||||||
>
|
<M.Body>
|
||||||
<section class="modal-card-body">
|
|
||||||
<div class="box is-shadowless is-fullwidth is-sideless">
|
|
||||||
<h2 class="title is-6">Signature</h2>
|
<h2 class="title is-6">Signature</h2>
|
||||||
<Hds::Copy::Snippet @textToCopy={{@signature}} @color="secondary" data-test-encrypted-value="signature" />
|
<Hds::Copy::Snippet
|
||||||
</div>
|
@textToCopy={{@signature}}
|
||||||
</section>
|
@color="secondary"
|
||||||
<footer class="modal-card-foot">
|
@container="#transit-sign-modal"
|
||||||
<button type="button" class="button is-primary" {{on "click" (fn (mut @isModalActive) false)}}>Close</button>
|
data-test-encrypted-value="signature"
|
||||||
</footer>
|
/>
|
||||||
</Modal>
|
</M.Body>
|
||||||
|
<M.Footer as |F|>
|
||||||
|
<Hds::Button @text="Close" {{on "click" F.close}} />
|
||||||
|
</M.Footer>
|
||||||
|
</Hds::Modal>
|
||||||
|
{{/if}}
|
||||||
@@ -192,16 +192,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<Modal @title="Results" @onClose={{action (mut @isModalActive) false}} @isActive={{@isModalActive}}>
|
{{#if @isModalActive}}
|
||||||
<section class="modal-card-body">
|
<Hds::Modal id="transit-verify-modal" @size="small" @onClose={{fn (mut @isModalActive) false}} as |M|>
|
||||||
<Hds::Alert @type="inline" @color={{if @valid "success" "critical"}} as |A|>
|
<M.Header>
|
||||||
<A.Title>{{if @valid "Valid" "Not Valid"}}</A.Title>
|
Results
|
||||||
<A.Description>
|
<Hds::Badge
|
||||||
|
@text={{if @valid "Valid" "Not Valid"}}
|
||||||
|
@size="large"
|
||||||
|
@color={{if @valid "success" "critical"}}
|
||||||
|
@icon={{if @valid "check-circle" "x-circle"}}
|
||||||
|
/>
|
||||||
|
</M.Header>
|
||||||
|
<M.Body>
|
||||||
The input is
|
The input is
|
||||||
{{if @valid "valid" "not valid"}}
|
{{if @valid "valid" "not valid"}}
|
||||||
for the given
|
for the given
|
||||||
{{if @signature "signature." "HMAC."}}
|
{{if @signature "signature." "HMAC."}}
|
||||||
</A.Description>
|
</M.Body>
|
||||||
</Hds::Alert>
|
<M.Footer as |F|>
|
||||||
</section>
|
<Hds::Button @text="Close" {{on "click" F.close}} />
|
||||||
</Modal>
|
</M.Footer>
|
||||||
|
</Hds::Modal>
|
||||||
|
{{/if}}
|
||||||
@@ -95,15 +95,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
class="button is-ghost"
|
@color="tertiary"
|
||||||
@filename={{this.keyFilename}}
|
@filename={{this.keyFilename}}
|
||||||
@data={{this.keyData}}
|
@data={{this.keyData}}
|
||||||
@extension="json"
|
@extension="json"
|
||||||
@stringify={{true}}
|
@stringify={{true}}
|
||||||
>
|
@text="Download keys"
|
||||||
<Icon @name="download" />
|
/>
|
||||||
Download keys
|
|
||||||
</DownloadButton>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Page.content>
|
</Page.content>
|
||||||
|
|||||||
@@ -29,14 +29,13 @@
|
|||||||
<Toolbar>
|
<Toolbar>
|
||||||
<ToolbarActions>
|
<ToolbarActions>
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
class="toolbar-link"
|
class="toolbar-button"
|
||||||
|
@color="secondary"
|
||||||
@filename={{this.model.name}}
|
@filename={{this.model.name}}
|
||||||
@data={{this.model.policy}}
|
@data={{this.model.policy}}
|
||||||
@extension={{if (eq this.policyType "acl") this.model.format "sentinel"}}
|
@extension={{if (eq this.policyType "acl") this.model.format "sentinel"}}
|
||||||
>
|
@text="Download policy"
|
||||||
Download policy
|
/>
|
||||||
<Chevron @isButton={{true}} />
|
|
||||||
</DownloadButton>
|
|
||||||
{{#if (and (not-eq this.model.id "root") (or this.capabilities.canUpdate this.capabilities.canDelete))}}
|
{{#if (and (not-eq this.model.id "root") (or this.capabilities.canUpdate this.capabilities.canDelete))}}
|
||||||
<ToolbarLink @route="vault.cluster.policy.edit" @model={{this.model.id}} data-test-policy-edit-toggle>
|
<ToolbarLink @route="vault.cluster.policy.edit" @model={{this.model.id}} data-test-policy-edit-toggle>
|
||||||
Edit policy
|
Edit policy
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
<h4 class="field-title has-bottom-padding-m is-fullwidth">
|
<h4 class="has-text-weight-bold is-size-7 has-bottom-padding-m is-fullwidth">
|
||||||
{{concat "PGP Key " this.pgpKeyFile.filename}}
|
{{concat "PGP Key " this.pgpKeyFile.filename}}
|
||||||
</h4>
|
</h4>
|
||||||
<Hds::Copy::Snippet
|
<Hds::Copy::Snippet
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
@textToCopy={{this.pgpKey}}
|
@textToCopy={{this.pgpKey}}
|
||||||
@color="secondary"
|
@color="secondary"
|
||||||
data-test-pgp-key-copy
|
data-test-pgp-key-copy
|
||||||
|
@container="#shamir-flow-modal"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="field is-grouped">
|
<div class="field is-grouped">
|
||||||
|
|||||||
@@ -14,5 +14,6 @@
|
|||||||
@text="Copy"
|
@text="Copy"
|
||||||
@textToCopy={{or @clipboardCode @codeBlock}}
|
@textToCopy={{or @clipboardCode @codeBlock}}
|
||||||
@isIconOnly={{@isIconOnly}}
|
@isIconOnly={{@isIconOnly}}
|
||||||
|
@container={{@container}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -3,17 +3,22 @@
|
|||||||
SPDX-License-Identifier: BUSL-1.1
|
SPDX-License-Identifier: BUSL-1.1
|
||||||
~}}
|
~}}
|
||||||
|
|
||||||
<Modal @title={{@title}} @onClose={{@onClose}} @isActive={{@isActive}} @type={{this.type}} @showCloseButton={{true}}>
|
{{#if @isActive}}
|
||||||
<section class="modal-card-body">
|
<Hds::Modal id="confirmation-modal" @onClose={{@onClose}} @color="critical" as |M|>
|
||||||
|
<M.Header data-test-confirmation-modal-title @icon="alert-triangle">
|
||||||
|
{{@title}}
|
||||||
|
</M.Header>
|
||||||
|
<M.Body>
|
||||||
{{yield}}
|
{{yield}}
|
||||||
<div class="modal-confirm-section">
|
<div class="has-top-padding-m">
|
||||||
<p class="has-text-weight-semibold is-size-6">
|
<p class="has-text-weight-semibold is-size-6">
|
||||||
Confirm
|
Confirm
|
||||||
</p>
|
</p>
|
||||||
<p class="sub-text has-top-bottom-margin-xxs">Type
|
<p class="sub-text has-top-bottom-margin-xxs">Type
|
||||||
<strong>{{this.confirmText}}</strong>
|
<strong>{{this.confirmText}}</strong>
|
||||||
to confirm
|
to confirm
|
||||||
{{this.toConfirmMsg}}</p>
|
{{@toConfirmMsg}}
|
||||||
|
</p>
|
||||||
<Input
|
<Input
|
||||||
@type="text"
|
@type="text"
|
||||||
@value={{this.confirmationInput}}
|
@value={{this.confirmationInput}}
|
||||||
@@ -21,22 +26,22 @@
|
|||||||
class="input has-margin-top"
|
class="input has-margin-top"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
data-test-confirmation-modal-input={{or @title true}}
|
data-test-confirmation-modal-input={{@title}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
|
<Hds::Button
|
||||||
|
@color="critical"
|
||||||
type="button"
|
type="button"
|
||||||
class="button {{this.buttonClass}}"
|
|
||||||
disabled={{not-eq this.confirmationInput this.confirmText}}
|
disabled={{not-eq this.confirmationInput this.confirmText}}
|
||||||
{{on "click" @onConfirm}}
|
{{on "click" @onConfirm}}
|
||||||
data-test-confirm-button={{or @title true}}
|
data-test-confirm-button={{@title}}
|
||||||
>
|
@text={{or @buttonText "Confirm"}}
|
||||||
{{this.buttonText}}
|
/>
|
||||||
</button>
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" @onClose}} data-test-cancel-button />
|
||||||
<button type="button" class="button is-secondary" {{on "click" @onClose}} data-test-cancel-button>
|
</Hds::ButtonSet>
|
||||||
Cancel
|
</M.Footer>
|
||||||
</button>
|
</Hds::Modal>
|
||||||
</footer>
|
{{/if}}
|
||||||
</Modal>
|
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright (c) HashiCorp, Inc.
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Component from '@glimmer/component';
|
import Component from '@glimmer/component';
|
||||||
/**
|
/**
|
||||||
* @module ConfirmationModal
|
* @module ConfirmationModal
|
||||||
* ConfirmationModal components are used to provide an alternative to ConfirmationButton that automatically prompts the user to fill in confirmation text before they can continue with a potentially destructive action. It is built off the Modal component
|
* ConfirmationModal components wrap the <Hds::Modal> component to present a critical (red) type-to-confirm modal.
|
||||||
|
* They are used for extremely destructive actions that require extra consideration before confirming.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```js
|
* ```js
|
||||||
@@ -15,6 +15,7 @@ import Component from '@glimmer/component';
|
|||||||
* @title="Do Dangerous Thing?"
|
* @title="Do Dangerous Thing?"
|
||||||
* @isActive={{isModalActive}}
|
* @isActive={{isModalActive}}
|
||||||
* @onClose={{action (mut isModalActive) false}}
|
* @onClose={{action (mut isModalActive) false}}
|
||||||
|
* @confirmText="yes"
|
||||||
* @onConfirmMsg="deleting this thing to delete."
|
* @onConfirmMsg="deleting this thing to delete."
|
||||||
* />
|
* />
|
||||||
* ```
|
* ```
|
||||||
@@ -23,30 +24,12 @@ import Component from '@glimmer/component';
|
|||||||
* @param {boolean} isActive - Controls whether the modal is "active" eg. visible or not.
|
* @param {boolean} isActive - Controls whether the modal is "active" eg. visible or not.
|
||||||
* @param {string} title - Title of the modal
|
* @param {string} title - Title of the modal
|
||||||
* @param {string} [confirmText=Yes] - The confirmation text that the user must type before continuing
|
* @param {string} [confirmText=Yes] - The confirmation text that the user must type before continuing
|
||||||
* @param {string} [toConfirmMsg=''] - Finishes the sentence "Type <confirmText> to confirm <toConfirmMsg>", default is an empty string (ex. 'secret deletion')
|
* @param {string} [toConfirmMsg] - Finishes the sentence "Type <confirmText> to confirm <toConfirmMsg>", default is an empty string (ex. 'secret deletion')
|
||||||
* @param {string} [buttonText=Confirm] - Button text on the confirm button
|
* @param {string} [buttonText=Confirm] - Button text on the confirm button
|
||||||
* @param {string} [buttonClass=is-danger] - extra class to add to confirm button (eg. "is-danger")
|
|
||||||
* @param {string} [type=warning] - The header styling based on type, passed into the message-types helper (in the Modal component).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class ConfirmationModal extends Component {
|
export default class ConfirmationModal extends Component {
|
||||||
get buttonClass() {
|
|
||||||
return this.args.buttonClass || 'is-danger';
|
|
||||||
}
|
|
||||||
|
|
||||||
get buttonText() {
|
|
||||||
return this.args.buttonText || 'Confirm';
|
|
||||||
}
|
|
||||||
|
|
||||||
get confirmText() {
|
get confirmText() {
|
||||||
return this.args.confirmText || 'Yes';
|
return this.args.confirmText || 'Yes';
|
||||||
}
|
}
|
||||||
|
|
||||||
get type() {
|
|
||||||
return this.args.type || 'warning';
|
|
||||||
}
|
|
||||||
|
|
||||||
get toConfirmMsg() {
|
|
||||||
return this.args.toConfirmMsg || '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,13 @@
|
|||||||
SPDX-License-Identifier: BUSL-1.1
|
SPDX-License-Identifier: BUSL-1.1
|
||||||
~}}
|
~}}
|
||||||
|
|
||||||
<button data-test-download-button type="button" {{on "click" this.handleDownload}} ...attributes>
|
<Hds::Button
|
||||||
{{yield}}
|
data-test-download-button
|
||||||
</button>
|
@icon={{if @hideIcon "" "download"}}
|
||||||
|
@text={{or @text "Download"}}
|
||||||
|
@color={{@color}}
|
||||||
|
@iconPosition={{or @iconPosition "leading"}}
|
||||||
|
@isIconOnly={{@isIconOnly}}
|
||||||
|
{{on "click" this.handleDownload}}
|
||||||
|
...attributes
|
||||||
|
/>
|
||||||
@@ -12,22 +12,20 @@ import { tracked } from '@glimmer/tracking';
|
|||||||
import { assert } from '@ember/debug';
|
import { assert } from '@ember/debug';
|
||||||
/**
|
/**
|
||||||
* @module DownloadButton
|
* @module DownloadButton
|
||||||
* DownloadButton components are an action button used to download data. Both the action text and icon are yielded.
|
* DownloadButton wraps an <Hds::Button> to perform a download action.
|
||||||
* * NOTE: when using in an engine, remember to add the 'download' service to its dependencies (in /engine.js) and map to it in /app.js
|
* * NOTE: when using in an engine, remember to add the 'download' service to its dependencies (in /engine.js) and map to it in /app.js
|
||||||
* [ember-docs](https://ember-engines.com/docs/services)
|
* [ember-docs](https://ember-engines.com/docs/services)
|
||||||
* @example
|
* @example
|
||||||
* ```js
|
* ```js
|
||||||
* <DownloadButton
|
* <DownloadButton
|
||||||
* class="button"
|
* @text="Download this stuff"
|
||||||
|
* @color="secondary"
|
||||||
* @data={{this.data}}
|
* @data={{this.data}}
|
||||||
* @filename={{this.filename}}
|
* @filename={{this.filename}}
|
||||||
* @mime={{this.mime}}
|
* @mime={{this.mime}}
|
||||||
* @extension={{this.extension}}
|
* @extension={{this.extension}}
|
||||||
* @stringify={{true}}
|
* @stringify={{true}}
|
||||||
* >
|
* />
|
||||||
* <Icon @name="download" />
|
|
||||||
* Download
|
|
||||||
* </DownloadButton>
|
|
||||||
* ```
|
* ```
|
||||||
* @param {string} [filename] - name of file that prefixes the ISO timestamp generated at download
|
* @param {string} [filename] - name of file that prefixes the ISO timestamp generated at download
|
||||||
* @param {string} [data] - data to download
|
* @param {string} [data] - data to download
|
||||||
@@ -35,6 +33,12 @@ import { assert } from '@ember/debug';
|
|||||||
* @param {string} [extension='txt'] - file extension, the download service uses this to determine the mimetype
|
* @param {string} [extension='txt'] - file extension, the download service uses this to determine the mimetype
|
||||||
* @param {boolean} [stringify=false] - argument to stringify the data before passing to the File constructor
|
* @param {boolean} [stringify=false] - argument to stringify the data before passing to the File constructor
|
||||||
* @param {callback} [onSuccess] - callback from parent to invoke if download is successful
|
* @param {callback} [onSuccess] - callback from parent to invoke if download is successful
|
||||||
|
* @param {boolean} [hideIcon=false] - renders the 'download' icon by default, pass true to hide (ex: when download button appears in a dropdown)
|
||||||
|
* * HDS ARGS https://helios.hashicorp.design/components/button?tab=code
|
||||||
|
* @param {string} [text="Download"] - button text, defaults to 'Download'
|
||||||
|
* @param {string} [color] - HDS default is primary, but there are four color options: primary, secondary, tertiary, and critical.
|
||||||
|
* @param {string} [iconPosition="leading"] - icon position, 'leading' (HDS default) or 'trailing'
|
||||||
|
* @param {boolean} [isIconOnly] - button only renders an icon, no text
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class DownloadButton extends Component {
|
export default class DownloadButton extends Component {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
@text="Copy"
|
@text="Copy"
|
||||||
@isIconOnly={{true}}
|
@isIconOnly={{true}}
|
||||||
@textToCopy={{@value}}
|
@textToCopy={{@value}}
|
||||||
class="transparent icon-only is-paddingless"
|
class="transparent has-padding-xxs"
|
||||||
data-test-copy-button
|
data-test-copy-button
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|||||||
@@ -39,14 +39,20 @@
|
|||||||
@text="Copy"
|
@text="Copy"
|
||||||
@isIconOnly={{true}}
|
@isIconOnly={{true}}
|
||||||
@textToCopy={{@value}}
|
@textToCopy={{@value}}
|
||||||
class="transparent icon-only is-paddingless"
|
class="transparent has-padding-xxs"
|
||||||
data-test-copy-button
|
data-test-copy-button
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if @allowDownload}}
|
{{#if @allowDownload}}
|
||||||
<button type="button" class="button download-button" {{on "click" (fn (mut this.modalOpen) true)}}>
|
<Hds::Button
|
||||||
<Icon data-test-download-icon @name="download" />
|
@text="Download secret value"
|
||||||
</button>
|
@icon="download"
|
||||||
|
@isIconOnly={{true}}
|
||||||
|
@color="tertiary"
|
||||||
|
class="has-padding-xxs"
|
||||||
|
data-test-download-icon
|
||||||
|
{{on "click" (fn (mut this.modalOpen) true)}}
|
||||||
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<button
|
<button
|
||||||
onclick={{this.toggleMask}}
|
onclick={{this.toggleMask}}
|
||||||
@@ -61,31 +67,25 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{! CONFIRM DOWNLOAD MODAL }}
|
{{! CONFIRM DOWNLOAD MODAL }}
|
||||||
{{#if @allowDownload}}
|
{{#if this.modalOpen}}
|
||||||
<Modal
|
<Hds::Modal @color="warning" id="confirm-download-modal" @onClose={{fn (mut this.modalOpen) false}} as |M|>
|
||||||
@title="Download secret value?"
|
<M.Header @icon="alert-triangle">
|
||||||
@onClose={{action (mut this.modalOpen) false}}
|
Download secret value?
|
||||||
@isActive={{this.modalOpen}}
|
</M.Header>
|
||||||
@type="warning"
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
This download is
|
This download is
|
||||||
<strong>unencrypted</strong>. Are you sure you want to download this secret data as plaintext?
|
<strong>unencrypted</strong>. Are you sure you want to download this secret data as plaintext?
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
|
<Hds::ButtonSet>
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
class="button is-primary"
|
|
||||||
@filename={{or @name "secret-value"}}
|
@filename={{or @name "secret-value"}}
|
||||||
@data={{@value}}
|
@data={{@value}}
|
||||||
@stringify={{true}}
|
@stringify={{true}}
|
||||||
aria-label="Download secret value"
|
|
||||||
@onSuccess={{fn (mut this.modalOpen) false}}
|
@onSuccess={{fn (mut this.modalOpen) false}}
|
||||||
>
|
/>
|
||||||
Download
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} />
|
||||||
</DownloadButton>
|
</Hds::ButtonSet>
|
||||||
<button type="button" class="button is-secondary" {{on "click" (fn (mut this.modalOpen) false)}}>
|
</M.Footer>
|
||||||
Cancel
|
</Hds::Modal>
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{{!
|
|
||||||
Copyright (c) HashiCorp, Inc.
|
|
||||||
SPDX-License-Identifier: BUSL-1.1
|
|
||||||
~}}
|
|
||||||
|
|
||||||
<EmberWormhole @to="modal-wormhole">
|
|
||||||
<div class="{{this.modalClass}} {{if this.isActive 'is-active'}}" data-test-modal-div ...attributes>
|
|
||||||
<div class="modal-background" role="button" {{on "click" @onClose}} data-test-modal-background={{@title}}></div>
|
|
||||||
<div class="modal-card">
|
|
||||||
<header class="modal-card-head">
|
|
||||||
<h2 class="modal-card-title title is-5" data-test-modal-title>
|
|
||||||
{{#if this.glyph}}
|
|
||||||
<Icon
|
|
||||||
class={{this.glyph.glyphClass}}
|
|
||||||
aria-hidden="true"
|
|
||||||
@name={{this.glyph.glyph}}
|
|
||||||
data-test-modal-glyph={{this.glyph.glyph}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
<span class={{if this.glyph "has-left-padding-xs"}}>{{capitalize @title}}</span>
|
|
||||||
</h2>
|
|
||||||
{{#if this.showCloseButton}}
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="icon-button has-text-grey"
|
|
||||||
aria-label="close"
|
|
||||||
{{on "click" @onClose}}
|
|
||||||
data-test-modal-close-button
|
|
||||||
>
|
|
||||||
<Icon @name="x-circle" class="close-icon" />
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
|
||||||
</header>
|
|
||||||
{{yield}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</EmberWormhole>
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Component from '@glimmer/component';
|
|
||||||
import { messageTypes } from 'core/helpers/message-types';
|
|
||||||
/**
|
|
||||||
* @module Modal
|
|
||||||
* Modal components are used to overlay content on top of the page. Has a darkened background,
|
|
||||||
* a title, and in order to close it you must pass an onClose function.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```js
|
|
||||||
* <Modal
|
|
||||||
* @title="Export attribution data"
|
|
||||||
* @type="info"
|
|
||||||
* @isActive={{this.showModal}}
|
|
||||||
* @showCloseButton={{true}}
|
|
||||||
* @onClose={{action (mut this.showModal) false}}
|
|
||||||
* >
|
|
||||||
* Whatever content pops up when the modal isActive!
|
|
||||||
* </Modal>
|
|
||||||
* ```
|
|
||||||
* @callback onClose
|
|
||||||
* @param {onClose} onClose - onClose is the action taken when someone clicks the modal background or close button (if shown).
|
|
||||||
* @param {boolean} isActive=false - whether or not modal displays
|
|
||||||
* @param {string} [title] - This text shows up in the header section of the modal. Only the first word should be capitalized.
|
|
||||||
* @param {boolean} [showCloseButton=false] - controls whether the close button in the top right corner shows.
|
|
||||||
* @param {string} [type=null] - The header styling based on type passed into the message-types helper.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default class ModalComponent extends Component {
|
|
||||||
get isActive() {
|
|
||||||
return this.args.isActive || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get showCloseButton() {
|
|
||||||
return this.args.showCloseButton || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get glyph() {
|
|
||||||
if (!this.args.type) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return messageTypes([this.args.type]);
|
|
||||||
}
|
|
||||||
|
|
||||||
get modalClass() {
|
|
||||||
if (!this.args.type) {
|
|
||||||
return 'modal';
|
|
||||||
}
|
|
||||||
return 'modal ' + messageTypes([this.args.type]).class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -42,7 +42,14 @@
|
|||||||
</p>
|
</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<JsonEditor @value={{get this.policyTemplates @policyType}} @mode="ruby" @readOnly={{true}} @showToolbar={{true}} />
|
<JsonEditor
|
||||||
|
@value={{get this.policyTemplates @policyType}}
|
||||||
|
@mode="ruby"
|
||||||
|
@readOnly={{true}}
|
||||||
|
@showToolbar={{true}}
|
||||||
|
{{! Passed to copy button }}
|
||||||
|
@container={{@container}}
|
||||||
|
/>
|
||||||
<div class="has-bottom-margin-m has-top-padding-s">
|
<div class="has-bottom-margin-m has-top-padding-s">
|
||||||
<p>
|
<p>
|
||||||
More information about
|
More information about
|
||||||
|
|||||||
@@ -14,28 +14,11 @@ import Component from '@glimmer/component';
|
|||||||
* @example
|
* @example
|
||||||
* <PolicyExample
|
* <PolicyExample
|
||||||
* @policyType={{@model.policyType}}
|
* @policyType={{@model.policyType}}
|
||||||
|
* @container="#search-select-modal"
|
||||||
* />
|
* />
|
||||||
*
|
|
||||||
* @example (in modal)
|
|
||||||
* <Modal
|
|
||||||
* @onClose={{fn (mut this.showTemplateModal) false}}
|
|
||||||
* @isActive={{this.showTemplateModal}}
|
|
||||||
* >
|
|
||||||
* <section class="modal-card-body">
|
|
||||||
* {{! code-mirror modifier does not render value initially until focus event fires }}
|
|
||||||
* {{! wait until the Modal is rendered and then show the PolicyExample (contains JsonEditor) }}
|
|
||||||
* {{#if this.showTemplateModal}}
|
|
||||||
* <PolicyExample @policyType={{@model.policyType}}/>
|
|
||||||
* {{/if}}
|
|
||||||
* </section>
|
|
||||||
* <div class="modal-card-head has-border-top-light">
|
|
||||||
* <button type="button" class="button" {{on "click" (fn (mut this.showTemplateModal) false)}} data-test-close-modal>
|
|
||||||
* Close
|
|
||||||
* </button>
|
|
||||||
* </div>
|
|
||||||
* </Modal>
|
|
||||||
* ```
|
* ```
|
||||||
* @param {string} policyType - policy type to decide which template to render; can either be "acl" or "rgp"
|
* @param {string} policyType - policy type to decide which template to render; can either be "acl" or "rgp"
|
||||||
|
* @param {string} container - selector for the container the example renders inside, passed to the copy button in JsonEditor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class PolicyExampleComponent extends Component {
|
export default class PolicyExampleComponent extends Component {
|
||||||
|
|||||||
@@ -83,32 +83,24 @@
|
|||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{! wait until user has selected 'create a new item' before rendering modal}}
|
{{#if this.showModal}}
|
||||||
{{#if this.nameInput}}
|
<Hds::Modal id="search-select-modal" @onClose={{fn (mut this.showModal) false}} as |M|>
|
||||||
<Modal
|
<M.Header data-test-modal-title>
|
||||||
@title="Create new {{singularize @id}}"
|
Create new
|
||||||
@onClose={{action (mut this.showModal) false}}
|
{{singularize @id}}
|
||||||
@isActive={{this.showModal}}
|
</M.Header>
|
||||||
@type="info"
|
<M.Body>
|
||||||
@showCloseButton={{false}}
|
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
{{#if @modalSubtext}}
|
{{#if @modalSubtext}}
|
||||||
<p class="has-bottom-margin-s" data-test-modal-subtext>
|
<p class="has-bottom-margin-s" data-test-modal-subtext>
|
||||||
{{@modalSubtext}}
|
{{@modalSubtext}}
|
||||||
</p>
|
</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if (has-block)}}
|
|
||||||
{{yield}}
|
|
||||||
{{else}}
|
|
||||||
{{! dynamically render template from modal-form/ folder}}
|
{{! dynamically render template from modal-form/ folder}}
|
||||||
{{! form must receive an @onSave and @onCancel arg that executes the callback}}
|
{{! form must receive an @onSave and @onCancel arg that executes the callback}}
|
||||||
{{component @modalFormTemplate nameInput=this.nameInput onSave=this.resetModal onCancel=this.resetModal}}
|
{{component @modalFormTemplate nameInput=this.nameInput onSave=this.resetModal onCancel=this.resetModal}}
|
||||||
{{/if}}
|
</M.Body>
|
||||||
</section>
|
</Hds::Modal>
|
||||||
</Modal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
@options={{this.dropdownOptions}}
|
@options={{this.dropdownOptions}}
|
||||||
@onChange={{this.selectOrCreate}}
|
@onChange={{this.selectOrCreate}}
|
||||||
@placeholderComponent={{component "search-select-placeholder"}}
|
@placeholderComponent={{component "search-select-placeholder"}}
|
||||||
|
@renderInPlace={{@renderInPlace}}
|
||||||
@verticalPosition="below"
|
@verticalPosition="below"
|
||||||
@disabled={{@disabled}}
|
@disabled={{@disabled}}
|
||||||
as |option|
|
as |option|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-ut
|
|||||||
* @param {string} [wildcardLabel] - string (singular) for rendering label tag beside a wildcard selection (i.e. 'role*'), for the number of items it includes, e.g. @wildcardLabel="role" -> "includes 4 roles"
|
* @param {string} [wildcardLabel] - string (singular) for rendering label tag beside a wildcard selection (i.e. 'role*'), for the number of items it includes, e.g. @wildcardLabel="role" -> "includes 4 roles"
|
||||||
* @param {string} [placeholder] - text you wish to replace the default "search" with
|
* @param {string} [placeholder] - text you wish to replace the default "search" with
|
||||||
* @param {boolean} [displayInherit=false] - if you need the search select component to display inherit instead of box.
|
* @param {boolean} [displayInherit=false] - if you need the search select component to display inherit instead of box.
|
||||||
|
* @param {boolean} [renderInPlace] - pass `true` when power select renders in a modal
|
||||||
* @param {function} [renderInfoTooltip] - receives each inputValue string and list of dropdownOptions as args, so parent can determine when to render a tooltip beside a selectedOption and the tooltip text. see 'oidc/provider-form.js'
|
* @param {function} [renderInfoTooltip] - receives each inputValue string and list of dropdownOptions as args, so parent can determine when to render a tooltip beside a selectedOption and the tooltip text. see 'oidc/provider-form.js'
|
||||||
* @param {boolean} [disabled] - if true sets the disabled property on the ember-power-select component and makes it unusable.
|
* @param {boolean} [disabled] - if true sets the disabled property on the ember-power-select component and makes it unusable.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -2,35 +2,34 @@
|
|||||||
Copyright (c) HashiCorp, Inc.
|
Copyright (c) HashiCorp, Inc.
|
||||||
SPDX-License-Identifier: BUSL-1.1
|
SPDX-License-Identifier: BUSL-1.1
|
||||||
~}}
|
~}}
|
||||||
|
{{! THIS COMPONENT RENDERS INSIDE A MODAL (must pass @container to copy buttons) }}
|
||||||
<section class="modal-card-body">
|
{{#if this.encodedToken}}
|
||||||
{{#if this.encodedToken}}
|
|
||||||
<p class="has-bottom-margin-l" data-test-dr-token-flow-step="show-token">
|
<p class="has-bottom-margin-l" data-test-dr-token-flow-step="show-token">
|
||||||
Below is the process and the values necessary to generate your operation token. Read the instructions carefully!
|
Below is the process and the values necessary to generate your operation token. Read the instructions carefully!
|
||||||
</p>
|
</p>
|
||||||
<div class="has-bottom-margin-m">
|
<div class="has-bottom-margin-m">
|
||||||
<div class="has-bottom-margin-xl">
|
<div class="has-bottom-margin-xl">
|
||||||
<h4 class="field-title">
|
<h4 class="has-text-weight-bold is-size-7">
|
||||||
Encoded operation token
|
Encoded operation token
|
||||||
</h4>
|
</h4>
|
||||||
<p class="help has-text-grey has-bottom-margin-xs">
|
<p class="help has-text-grey has-bottom-margin-xs">
|
||||||
This is a one-time token that will be used to generate the operation token. Please save it.
|
This is a one-time token that will be used to generate the operation token. Please save it.
|
||||||
</p>
|
</p>
|
||||||
<Hds::Copy::Snippet @textToCopy={{this.encodedToken}} data-test-shamir-encoded-token />
|
<Hds::Copy::Snippet @textToCopy={{this.encodedToken}} @container="#shamir-flow-modal" data-test-shamir-encoded-token />
|
||||||
</div>
|
</div>
|
||||||
{{#if this.otp}}
|
{{#if this.otp}}
|
||||||
<div class="has-bottom-margin-xl">
|
<div class="has-bottom-margin-xl">
|
||||||
<h4 class="field-title">
|
<h4 class="has-text-weight-bold is-size-7">
|
||||||
One time password (OTP)
|
One time password (OTP)
|
||||||
</h4>
|
</h4>
|
||||||
<p class="help has-text-grey has-bottom-margin-xs">
|
<p class="help has-text-grey has-bottom-margin-xs">
|
||||||
This OTP will be used to decode the generated operation token. Please save it.
|
This OTP will be used to decode the generated operation token. Please save it.
|
||||||
</p>
|
</p>
|
||||||
<Hds::Copy::Snippet @textToCopy={{this.otp}} />
|
<Hds::Copy::Snippet @textToCopy={{this.otp}} @container="#shamir-flow-modal" />
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="has-bottom-margin-xl">
|
<div class="has-bottom-margin-xl">
|
||||||
<h4 class="field-title">
|
<h4 class="has-text-weight-bold is-size-7">
|
||||||
DR operation token command
|
DR operation token command
|
||||||
</h4>
|
</h4>
|
||||||
<p class="help has-text-grey has-bottom-margin-xs">
|
<p class="help has-text-grey has-bottom-margin-xs">
|
||||||
@@ -51,17 +50,15 @@
|
|||||||
)
|
)
|
||||||
as |cmd|
|
as |cmd|
|
||||||
}}
|
}}
|
||||||
<CodeSnippet @codeBlock={{cmd}} />
|
<CodeSnippet @codeBlock={{cmd}} @container="#shamir-flow-modal" />
|
||||||
{{/let}}
|
{{/let}}
|
||||||
{{! template-lint-enable quotes }}
|
{{! template-lint-enable quotes }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" class="button is-primary" {{on "click" this.onCancelClose}}>
|
<Hds::Button {{on "click" this.onCancelClose}} @text="Clear & Close" />
|
||||||
Clear & Close
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
{{else if this.started}}
|
{{else if this.started}}
|
||||||
<Shamir::Form
|
<Shamir::Form
|
||||||
@action={{@action}}
|
@action={{@action}}
|
||||||
@progress={{this.progress}}
|
@progress={{this.progress}}
|
||||||
@@ -79,7 +76,7 @@
|
|||||||
secondary Disaster Recovery cluster.
|
secondary Disaster Recovery cluster.
|
||||||
</p>
|
</p>
|
||||||
</Shamir::Form>
|
</Shamir::Form>
|
||||||
{{else if this.generateWithPGP}}
|
{{else if this.generateWithPGP}}
|
||||||
<ChoosePgpKeyForm
|
<ChoosePgpKeyForm
|
||||||
@onCancel={{fn (mut this.generateWithPGP) false}}
|
@onCancel={{fn (mut this.generateWithPGP) false}}
|
||||||
@onSubmit={{this.usePgpKey}}
|
@onSubmit={{this.usePgpKey}}
|
||||||
@@ -88,7 +85,7 @@
|
|||||||
@buttonText="Generate operation token"
|
@buttonText="Generate operation token"
|
||||||
data-test-dr-token-flow-step="choose-pgp"
|
data-test-dr-token-flow-step="choose-pgp"
|
||||||
/>
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{! Generate token flow not started }}
|
{{! Generate token flow not started }}
|
||||||
<form
|
<form
|
||||||
{{on "submit" this.startGenerate}}
|
{{on "submit" this.startGenerate}}
|
||||||
@@ -97,18 +94,22 @@
|
|||||||
data-test-dr-token-flow-step="begin"
|
data-test-dr-token-flow-step="begin"
|
||||||
>
|
>
|
||||||
<MessageError @errors={{this.errors}} />
|
<MessageError @errors={{this.errors}} />
|
||||||
<div class="has-bottom-margin-m" data-test-shamir-modal-body>
|
<div class="has-bottom-margin-m">
|
||||||
<p>
|
<p>
|
||||||
Updating or promoting this cluster requires an operation token, generated by inputting the root key shares. If
|
Updating or promoting this cluster requires an operation token, generated by inputting the root key shares. If you'd
|
||||||
you'd like to first encrypt the token with a PGP Key, click "Encrypt with PGP key" below, otherwise we can begin
|
like to first encrypt the token with a PGP Key, click "Encrypt with PGP key" below, otherwise we can begin generation
|
||||||
generation of the operation token.
|
of the operation token.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field is-grouped is-flex-center">
|
<div class="field is-grouped is-flex-center">
|
||||||
<div class="control is-flex-row">
|
<div class="control is-flex-row">
|
||||||
<button type="button" class="link" {{on "click" (fn (mut this.generateWithPGP) true)}} data-test-use-pgp-key-cta>
|
<Hds::Button
|
||||||
Provide PGP Key
|
@color="tertiary"
|
||||||
</button>
|
@icon="key"
|
||||||
|
{{on "click" (fn (mut this.generateWithPGP) true)}}
|
||||||
|
data-test-use-pgp-key-cta
|
||||||
|
@text="Provide PGP Key"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<span class="has-side-padding-s">
|
<span class="has-side-padding-s">
|
||||||
@@ -116,16 +117,16 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button type="submit" class="button is-primary" data-test-generate-token-cta>
|
<Hds::Button type="submit" data-test-generate-token-cta @text="Generate operation token" />
|
||||||
Generate operation token
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</section>
|
<hr class="has-background-gray-100" />
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
|
||||||
<button type="button" class="button is-secondary" {{on "click" this.onCancelClose}} data-test-shamir-modal-cancel-button>
|
<Hds::Button
|
||||||
{{if this.encodedToken "Close" "Cancel"}}
|
@color="secondary"
|
||||||
</button>
|
{{on "click" this.onCancelClose}}
|
||||||
</footer>
|
data-test-shamir-modal-cancel-button
|
||||||
|
@text={{if this.encodedToken "Close" "Cancel"}}
|
||||||
|
/>
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<h4 class="hds-alert__title hds-font-weight-semibold">
|
<h4 class="hds-alert__title hds-font-weight-semibold">
|
||||||
One Time Password (otp)
|
One Time Password (otp)
|
||||||
</h4>
|
</h4>
|
||||||
<Hds::Copy::Snippet data-test-otp @textToCopy={{@otp}} @color="secondary" />
|
<Hds::Copy::Snippet data-test-otp @textToCopy={{@otp}} @color="secondary" @container="#shamir-flow-modal" />
|
||||||
</A.Description>
|
</A.Description>
|
||||||
</Hds::Alert>
|
</Hds::Alert>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|||||||
@@ -37,11 +37,6 @@ export const MESSAGE_TYPES = {
|
|||||||
glyph: 'loading',
|
glyph: 'loading',
|
||||||
text: 'Loading',
|
text: 'Loading',
|
||||||
},
|
},
|
||||||
rotation: {
|
|
||||||
class: 'is-info',
|
|
||||||
glyphClass: 'has-text-grey',
|
|
||||||
glyph: 'rotate-cw',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function messageTypes([type]) {
|
export function messageTypes([type]) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="button is-secondary"
|
class="button is-secondary"
|
||||||
onclick={{action (mut this.isModalActive) true}}
|
onclick={{action (mut this.isModalActive) true}}
|
||||||
data-test-replication-action-trigger
|
data-test-replication-action-trigger="demote"
|
||||||
>
|
>
|
||||||
Demote
|
Demote
|
||||||
</button>
|
</button>
|
||||||
@@ -30,7 +30,6 @@
|
|||||||
@title="Demote to secondary?"
|
@title="Demote to secondary?"
|
||||||
@onClose={{action (mut this.isModalActive) false}}
|
@onClose={{action (mut this.isModalActive) false}}
|
||||||
@isActive={{this.isModalActive}}
|
@isActive={{this.isModalActive}}
|
||||||
@buttonClass="is-primary"
|
|
||||||
@confirmText={{this.model.replicationModeForDisplay}}
|
@confirmText={{this.model.replicationModeForDisplay}}
|
||||||
@toConfirmMsg="demoting this cluster"
|
@toConfirmMsg="demoting this cluster"
|
||||||
@onConfirm={{action "onSubmit" "demote" this.model.replicationAttrs.modeForUrl}}
|
@onConfirm={{action "onSubmit" "demote" this.model.replicationAttrs.modeForUrl}}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="button is-danger"
|
class="button is-danger"
|
||||||
onclick={{action (mut this.isModalActive) true}}
|
onclick={{action (mut this.isModalActive) true}}
|
||||||
data-test-replication-action-trigger
|
data-test-replication-action-trigger="disable"
|
||||||
>
|
>
|
||||||
Disable Replication
|
Disable Replication
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -25,16 +25,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Modal
|
{{#if this.isModalActive}}
|
||||||
@title="Generate operation token"
|
<Hds::Modal id="shamir-flow-modal" @color="warning" @onClose={{action (mut this.isModalActive) false}} as |M|>
|
||||||
@onClose={{action (mut this.isModalActive) false}}
|
<M.Header>
|
||||||
@isActive={{this.isModalActive}}
|
Generate operation token
|
||||||
@type="warning"
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
{{#if this.isModalActive}}
|
|
||||||
{{! Wrapped in if statement so the Shamir constructor fires on modal open }}
|
|
||||||
<Shamir::DrTokenFlow @action="generate-dr-operation-token" @onCancel={{action (mut this.isModalActive) false}} />
|
<Shamir::DrTokenFlow @action="generate-dr-operation-token" @onCancel={{action (mut this.isModalActive) false}} />
|
||||||
|
</M.Body>
|
||||||
{{! Section & Footer is in child component since the form must do side effects on cancel }}
|
{{! Section & Footer is in child component since the form must do side effects on cancel }}
|
||||||
{{/if}}
|
</Hds::Modal>
|
||||||
</Modal>
|
{{/if}}
|
||||||
@@ -20,30 +20,28 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="button is-tertiary"
|
class="button is-tertiary"
|
||||||
onclick={{action (mut this.isModalActive) true}}
|
onclick={{action (mut this.isModalActive) true}}
|
||||||
data-test-replication-action-trigger
|
data-test-replication-action-trigger="promote"
|
||||||
>
|
>
|
||||||
Promote
|
Promote
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Modal
|
{{#if this.isModalActive}}
|
||||||
@title="Promote cluster?"
|
<Hds::Modal id="replication-promote-modal" @color="warning" @onClose={{fn (mut this.isModalActive) false}} as |M|>
|
||||||
@onClose={{action (mut this.isModalActive) false}}
|
<M.Header @icon="alert-triangle">
|
||||||
@isActive={{this.isModalActive}}
|
Promote cluster?
|
||||||
@type="warning"
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
{{#if (eq this.replicationMode "dr")}}
|
{{#if (eq this.replicationMode "dr")}}
|
||||||
<p class="has-bottom-margin-m">
|
<p class="has-bottom-margin-m">
|
||||||
To promote this DR Replication Secondary to a primary, enter the DR Operation token.
|
To promote this DR Replication Secondary to a primary, enter the DR Operation token.
|
||||||
</p>
|
</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<p class="has-bottom-margin-m">
|
<p class="has-bottom-margin-m">
|
||||||
Vault Replication is not designed for active-active usage. Enabling two primaries should never be done, as it can lead
|
Vault Replication is not designed for active-active usage. Enabling two primaries should never be done, as it can
|
||||||
to data loss if they or their secondaries are ever reconnected. If the cluster has a primary, be sure to demote it
|
lead to data loss if they or their secondaries are ever reconnected. If the cluster has a primary, be sure to demote
|
||||||
before promoting a secondary.
|
it before promoting a secondary.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div data-test-promote-dr-inputs>
|
<div data-test-promote-dr-inputs>
|
||||||
@@ -68,7 +66,12 @@
|
|||||||
<em class="is-optional">(optional)</em>
|
<em class="is-optional">(optional)</em>
|
||||||
</label>
|
</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<Input class="input" id="primary_cluster_addr" name="primary_cluster_addr" @value={{this.primary_cluster_addr}} />
|
<Input
|
||||||
|
class="input"
|
||||||
|
id="primary_cluster_addr"
|
||||||
|
name="primary_cluster_addr"
|
||||||
|
@value={{this.primary_cluster_addr}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p class="help">
|
<p class="help">
|
||||||
Overrides the cluster address that the primary gives to secondary nodes.
|
Overrides the cluster address that the primary gives to secondary nodes.
|
||||||
@@ -94,14 +97,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
type="button"
|
<Hds::Button
|
||||||
class="button is-primary"
|
|
||||||
disabled={{if (and (eq this.replicationMode "dr") (not this.dr_operation_token_promote)) true}}
|
disabled={{if (and (eq this.replicationMode "dr") (not this.dr_operation_token_promote)) true}}
|
||||||
onclick={{action
|
{{on
|
||||||
"onSubmit"
|
"click"
|
||||||
|
(fn
|
||||||
|
this.onSubmit
|
||||||
"promote"
|
"promote"
|
||||||
this.model.replicationAttrs.modeForUrl
|
this.model.replicationAttrs.modeForUrl
|
||||||
(hash
|
(hash
|
||||||
@@ -109,18 +113,13 @@
|
|||||||
primary_cluster_addr=this.primary_cluster_addr
|
primary_cluster_addr=this.primary_cluster_addr
|
||||||
force=this.force
|
force=this.force
|
||||||
)
|
)
|
||||||
|
)
|
||||||
}}
|
}}
|
||||||
data-test-promote-confirm-button
|
data-test-confirm-button
|
||||||
>
|
@text="Promote"
|
||||||
Promote
|
/>
|
||||||
</button>
|
<Hds::Button @color="secondary" @text="Cancel" {{on "click" F.close}} data-test-promote-cancel-button />
|
||||||
<button
|
</Hds::ButtonSet>
|
||||||
type="button"
|
</M.Footer>
|
||||||
class="button is-secondary"
|
</Hds::Modal>
|
||||||
onclick={{action (mut this.isModalActive) false}}
|
{{/if}}
|
||||||
data-test-promote-cancel-button
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
@@ -18,36 +18,28 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="button is-secondary"
|
class="button is-secondary"
|
||||||
onclick={{action (mut this.isModalActive) true}}
|
onclick={{action (mut this.isModalActive) true}}
|
||||||
data-test-replication-action-trigger
|
data-test-replication-action-trigger="recover"
|
||||||
>
|
>
|
||||||
Recover
|
Recover
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Modal
|
{{#if this.isModalActive}}
|
||||||
@title="Begin recovery?"
|
<Hds::Modal id="replication-recover-modal" @color="warning" @onClose={{fn (mut this.isModalActive) false}} as |M|>
|
||||||
@onClose={{action (mut this.isModalActive) false}}
|
<M.Header @icon="alert-triangle">
|
||||||
@isActive={{this.isModalActive}}
|
Begin recovery?
|
||||||
@type="warning"
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p>
|
<p>
|
||||||
If replication is in an adverse state, we can begin recovery. This will attempt to recover to continue syncing.
|
If replication is in an adverse state, we can begin recovery. This will attempt to recover to continue syncing.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button type="button" class="button is-primary" onclick={{action "onSubmit" "recover"}} data-test-recover-confirm-button>
|
<Hds::ButtonSet>
|
||||||
Recover
|
<Hds::Button @text="Recover" {{on "click" (fn this.onSubmit "recover")}} data-test-confirm-button />
|
||||||
</button>
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} data-test-recover-cancel-button />
|
||||||
<button
|
</Hds::ButtonSet>
|
||||||
type="button"
|
</M.Footer>
|
||||||
class="button is-secondary"
|
</Hds::Modal>
|
||||||
onclick={{action (mut this.isModalActive) false}}
|
{{/if}}
|
||||||
data-test-recover-cancel-button
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
@@ -17,20 +17,18 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="button is-secondary"
|
class="button is-secondary"
|
||||||
onclick={{action (mut this.isModalActive) true}}
|
onclick={{action (mut this.isModalActive) true}}
|
||||||
data-test-replication-action-trigger
|
data-test-replication-action-trigger="reindex"
|
||||||
>
|
>
|
||||||
Reindex
|
Reindex
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Modal
|
{{#if this.isModalActive}}
|
||||||
@title="Begin reindex?"
|
<Hds::Modal id="replication-reindex-modal" @color="warning" @onClose={{fn (mut this.isModalActive) false}} as |M|>
|
||||||
@onClose={{action (mut this.isModalActive) false}}
|
<M.Header @icon="alert-triangle">
|
||||||
@isActive={{this.isModalActive}}
|
Begin reindex?
|
||||||
@type="warning"
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p class="has-bottom-margin-m">
|
<p class="has-bottom-margin-m">
|
||||||
Reindexing can cause a very long delay depending on the number and size of objects in the data store.
|
Reindexing can cause a very long delay depending on the number and size of objects in the data store.
|
||||||
{{if this.model.replicationAttrs.isPrimary "You should always re-index your secondary first."}}
|
{{if this.model.replicationAttrs.isPrimary "You should always re-index your secondary first."}}
|
||||||
@@ -40,18 +38,12 @@
|
|||||||
{{if this.model.replicationAttrs.isPrimary "not"}}
|
{{if this.model.replicationAttrs.isPrimary "not"}}
|
||||||
be able to use Vault during this time.
|
be able to use Vault during this time.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button type="button" class="button is-primary" onclick={{action "onSubmit" "reindex"}} data-test-reindex-confirm-button>
|
<Hds::ButtonSet>
|
||||||
Reindex
|
<Hds::Button @text="Reindex" {{on "click" (fn this.onSubmit "reindex")}} data-test-confirm-button />
|
||||||
</button>
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} data-test-reindex-cancel-button />
|
||||||
<button
|
</Hds::ButtonSet>
|
||||||
type="button"
|
</M.Footer>
|
||||||
class="button is-secondary"
|
</Hds::Modal>
|
||||||
onclick={{action (mut this.isModalActive) false}}
|
{{/if}}
|
||||||
data-test-reindex-cancel-button
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
@@ -18,21 +18,19 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="button is-secondary"
|
class="button is-secondary"
|
||||||
onclick={{action (mut this.isModalActive) true}}
|
onclick={{action (mut this.isModalActive) true}}
|
||||||
data-test-update-primary-action-trigger
|
data-test-replication-action-trigger="update-primary"
|
||||||
>
|
>
|
||||||
Update
|
Update
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Modal
|
{{#if this.isModalActive}}
|
||||||
@title="Update primary"
|
<Hds::Modal id="replication-update-primary-modal" @color="warning" @onClose={{fn (mut this.isModalActive) false}} as |M|>
|
||||||
@onClose={{action (mut this.isModalActive) false}}
|
<M.Header @icon="alert-triangle">
|
||||||
@isActive={{this.isModalActive}}
|
Update primary
|
||||||
@type="warning"
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p class="has-bottom-margin-m">
|
<p class="has-bottom-margin-m">
|
||||||
Use a secondary activation token to change this secondary’s assigned primary. This does not wipe all data in the
|
Use a secondary activation token to change this secondary’s assigned primary. This does not wipe all data in the
|
||||||
cluster.
|
cluster.
|
||||||
@@ -101,13 +99,14 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
type="button"
|
<Hds::Button
|
||||||
class="button is-primary"
|
{{on
|
||||||
onclick={{action
|
"click"
|
||||||
"onSubmit"
|
(fn
|
||||||
|
this.onSubmit
|
||||||
"update-primary"
|
"update-primary"
|
||||||
this.model.replicationAttrs.modeForUrl
|
this.model.replicationAttrs.modeForUrl
|
||||||
(hash
|
(hash
|
||||||
@@ -117,18 +116,13 @@
|
|||||||
ca_path=this.ca_path
|
ca_path=this.ca_path
|
||||||
ca_file=this.ca_file
|
ca_file=this.ca_file
|
||||||
)
|
)
|
||||||
|
)
|
||||||
}}
|
}}
|
||||||
data-test-confirm-action-trigger
|
data-test-confirm-button
|
||||||
>
|
@text="Update"
|
||||||
Update
|
/>
|
||||||
</button>
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} data-test-update-primary-cancel-button />
|
||||||
<button
|
</Hds::ButtonSet>
|
||||||
type="button"
|
</M.Footer>
|
||||||
class="button is-secondary"
|
</Hds::Modal>
|
||||||
onclick={{action (mut this.isModalActive) false}}
|
{{/if}}
|
||||||
data-test-update-primary-cancel-button
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
export { default } from 'core/components/modal';
|
|
||||||
@@ -24,7 +24,6 @@
|
|||||||
"ember-router-helpers": "*",
|
"ember-router-helpers": "*",
|
||||||
"ember-svg-jar": "*",
|
"ember-svg-jar": "*",
|
||||||
"ember-truth-helpers": "*",
|
"ember-truth-helpers": "*",
|
||||||
"ember-wormhole": "*",
|
|
||||||
"escape-string-regexp": "*",
|
"escape-string-regexp": "*",
|
||||||
"@hashicorp/ember-flight-icons": "*",
|
"@hashicorp/ember-flight-icons": "*",
|
||||||
"@hashicorp/flight-icons": "*",
|
"@hashicorp/flight-icons": "*",
|
||||||
|
|||||||
@@ -8,14 +8,13 @@
|
|||||||
<ToolbarActions>
|
<ToolbarActions>
|
||||||
{{#if this.model}}
|
{{#if this.model}}
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
class="toolbar-link"
|
class="toolbar-button"
|
||||||
|
@color="secondary"
|
||||||
@filename={{concat this.model.ca.id "-ca"}}
|
@filename={{concat this.model.ca.id "-ca"}}
|
||||||
@data={{this.model.ca.caPem}}
|
@data={{this.model.ca.caPem}}
|
||||||
@extension="pem"
|
@extension="pem"
|
||||||
>
|
@text="Download CA cert"
|
||||||
Download CA cert
|
/>
|
||||||
<Chevron @isButton={{true}} />
|
|
||||||
</DownloadButton>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<ToolbarLink @route="configure" data-test-kmip-link-configure>
|
<ToolbarLink @route="configure" data-test-kmip-link-configure>
|
||||||
Configure
|
Configure
|
||||||
|
|||||||
@@ -103,26 +103,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if this.showConfirm}}
|
{{#if this.showConfirm}}
|
||||||
<Modal
|
<Hds::Modal id="kubernetes-edit-config-modal" @onClose={{fn (mut this.showConfirm) false}} @color="warning" as |M|>
|
||||||
@title="Edit configuration"
|
<M.Header @icon="alert-triangle">
|
||||||
@type="warning"
|
Edit configuration
|
||||||
@isActive={{this.showConfirm}}
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body data-test-edit-config-body>
|
||||||
@onClose={{fn (mut this.showConfirm) false}}
|
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p>
|
<p>
|
||||||
Making changes to your configuration may affect how Vault will reach the Kubernetes API and authenticate with it. Are
|
Making changes to your configuration may affect how Vault will reach the Kubernetes API and authenticate with it. Are
|
||||||
you sure?
|
you sure?
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button data-test-config-confirm type="button" class="button is-primary" {{on "click" (perform this.save)}}>
|
<Hds::ButtonSet>
|
||||||
Confirm
|
<Hds::Button data-test-config-confirm {{on "click" (perform this.save)}} @text="Confirm" />
|
||||||
</button>
|
<Hds::Button {{on "click" F.close}} @color="secondary" @text="Cancel" />
|
||||||
<button type="button" class="button" onclick={{fn (mut this.showConfirm) false}}>
|
</Hds::ButtonSet>
|
||||||
Cancel
|
</M.Footer>
|
||||||
</button>
|
</Hds::Modal>
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -1,16 +1,23 @@
|
|||||||
<button type="button" class="toolbar-link" {{on "click" (fn (mut this.modalOpen) true)}} data-test-kv-delete={{@mode}}>
|
<Hds::Button
|
||||||
{{yield}}
|
@text={{or @text (capitalize @mode)}}
|
||||||
</button>
|
@color="secondary"
|
||||||
|
class="toolbar-button"
|
||||||
|
{{on "click" (fn (mut this.modalOpen) true)}}
|
||||||
|
data-test-kv-delete={{@mode}}
|
||||||
|
/>
|
||||||
|
|
||||||
{{#if this.modalOpen}}
|
{{#if this.modalOpen}}
|
||||||
<Modal
|
<Hds::Modal
|
||||||
@title={{this.modalDisplay.title}}
|
id="kv-delete-modal-{{@mode}}"
|
||||||
|
@color={{this.modalDisplay.color}}
|
||||||
@onClose={{fn (mut this.modalOpen) false}}
|
@onClose={{fn (mut this.modalOpen) false}}
|
||||||
@isActive={{this.modalOpen}}
|
|
||||||
@type={{this.modalDisplay.type}}
|
|
||||||
@showCloseButton={{true}}
|
|
||||||
data-test-delete-modal
|
data-test-delete-modal
|
||||||
|
as |M|
|
||||||
>
|
>
|
||||||
<section class="modal-card-body">
|
<M.Header data-test-modal-title @icon="trash">
|
||||||
|
{{this.modalDisplay.title}}
|
||||||
|
</M.Header>
|
||||||
|
<M.Body>
|
||||||
<p class="has-bottom-margin-s">
|
<p class="has-bottom-margin-s">
|
||||||
{{this.modalDisplay.intro}}
|
{{this.modalDisplay.intro}}
|
||||||
</p>
|
</p>
|
||||||
@@ -45,19 +52,19 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
type="button"
|
<Hds::Button
|
||||||
class="button {{if (eq this.modalDisplay.type 'danger') 'is-danger-outlined' 'is-warning-outlined'}}"
|
@text="Confirm"
|
||||||
{{on "click" this.onDelete}}
|
{{on "click" this.onDelete}}
|
||||||
|
@color={{if (eq this.modalDisplay.color "critical") this.modalDisplay.color}}
|
||||||
data-test-delete-modal-confirm
|
data-test-delete-modal-confirm
|
||||||
>
|
/>
|
||||||
Confirm
|
|
||||||
</button>
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} />
|
||||||
<button type="button" class="button is-secondary" {{on "click" (fn (mut this.modalOpen) false)}}>
|
|
||||||
Cancel
|
</Hds::ButtonSet>
|
||||||
</button>
|
</M.Footer>
|
||||||
</footer>
|
</Hds::Modal>
|
||||||
</Modal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -21,6 +21,7 @@ import { assert } from '@ember/debug';
|
|||||||
* @param {string} mode - delete, delete-metadata, or destroy.
|
* @param {string} mode - delete, delete-metadata, or destroy.
|
||||||
* @param {object} secret - The kv/data model.
|
* @param {object} secret - The kv/data model.
|
||||||
* @param {object} [metadata] - The kv/metadata model. It is only required when mode is "delete" or "metadata-delete".
|
* @param {object} [metadata] - The kv/metadata model. It is only required when mode is "delete" or "metadata-delete".
|
||||||
|
* @param {string} [text] - Button text that renders in KV v2 toolbar, defaults to capitalize @mode
|
||||||
* @param {callback} onDelete - callback function fired to handle delete event.
|
* @param {callback} onDelete - callback function fired to handle delete event.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -34,20 +35,20 @@ export default class KvDeleteModal extends Component {
|
|||||||
case 'delete':
|
case 'delete':
|
||||||
return {
|
return {
|
||||||
title: 'Delete version?',
|
title: 'Delete version?',
|
||||||
type: 'warning',
|
color: 'warning',
|
||||||
intro:
|
intro:
|
||||||
'There are two ways to delete a version of a secret. Both delete actions can be undeleted later. How would you like to proceed?',
|
'There are two ways to delete a version of a secret. Both delete actions can be undeleted later. How would you like to proceed?',
|
||||||
};
|
};
|
||||||
case 'destroy':
|
case 'destroy':
|
||||||
return {
|
return {
|
||||||
title: 'Destroy version?',
|
title: 'Destroy version?',
|
||||||
type: 'danger',
|
color: 'critical',
|
||||||
intro: `This action will permanently destroy Version ${this.args.version} of the secret, and the secret data cannot be read or recovered later.`,
|
intro: `This action will permanently destroy Version ${this.args.version} of the secret, and the secret data cannot be read or recovered later.`,
|
||||||
};
|
};
|
||||||
case 'delete-metadata':
|
case 'delete-metadata':
|
||||||
return {
|
return {
|
||||||
title: 'Delete metadata and secret data?',
|
title: 'Delete metadata and secret data?',
|
||||||
type: 'danger',
|
color: 'critical',
|
||||||
intro:
|
intro:
|
||||||
'This will permanently delete the metadata and versions of the secret. All version history will be removed. This cannot be undone.',
|
'This will permanently delete the metadata and versions of the secret. All version history will be removed. This cannot be undone.',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,14 +34,10 @@
|
|||||||
@metadata={{@metadata}}
|
@metadata={{@metadata}}
|
||||||
@onDelete={{this.handleDestruction}}
|
@onDelete={{this.handleDestruction}}
|
||||||
@version={{this.version}}
|
@version={{this.version}}
|
||||||
>
|
/>
|
||||||
Delete
|
|
||||||
</KvDeleteModal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if this.showDestroy}}
|
{{#if this.showDestroy}}
|
||||||
<KvDeleteModal @mode="destroy" @secret={{@secret}} @onDelete={{this.handleDestruction}} @version={{this.version}}>
|
<KvDeleteModal @mode="destroy" @secret={{@secret}} @onDelete={{this.handleDestruction}} @version={{this.version}} />
|
||||||
Destroy
|
|
||||||
</KvDeleteModal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if (or @secret.canReadData @secret.canReadMetadata @secret.canEditData)}}
|
{{#if (or @secret.canReadData @secret.canReadMetadata @secret.canEditData)}}
|
||||||
<div class="toolbar-separator"></div>
|
<div class="toolbar-separator"></div>
|
||||||
|
|||||||
@@ -10,9 +10,12 @@
|
|||||||
|
|
||||||
<:toolbarActions>
|
<:toolbarActions>
|
||||||
{{#if @secret.canDeleteMetadata}}
|
{{#if @secret.canDeleteMetadata}}
|
||||||
<KvDeleteModal @mode="delete-metadata" @metadata={{@metadata}} @onDelete={{this.onDelete}}>
|
<KvDeleteModal
|
||||||
Permanently delete
|
@mode="delete-metadata"
|
||||||
</KvDeleteModal>
|
@metadata={{@metadata}}
|
||||||
|
@onDelete={{this.onDelete}}
|
||||||
|
@text="Permanently delete"
|
||||||
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if @secret.canUpdateMetadata}}
|
{{#if @secret.canUpdateMetadata}}
|
||||||
<ToolbarLink @route="secret.metadata.edit" data-test-edit-metadata>Edit metadata</ToolbarLink>
|
<ToolbarLink @route="secret.metadata.edit" data-test-edit-metadata>Edit metadata</ToolbarLink>
|
||||||
|
|||||||
@@ -39,37 +39,35 @@
|
|||||||
</OverviewCard>
|
</OverviewCard>
|
||||||
|
|
||||||
{{#if this.selectedStatus}}
|
{{#if this.selectedStatus}}
|
||||||
<Modal
|
<Hds::Modal id="account-check-in-modal" @onClose={{fn (mut this.selectedStatus) undefined}} as |M|>
|
||||||
@title="Account Check-in"
|
<M.Header>
|
||||||
@isActive={{this.selectedStatus}}
|
Account Check-in
|
||||||
@showCloseButton={{true}}
|
</M.Header>
|
||||||
@onClose={{fn (mut this.selectedStatus) undefined}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p>
|
<p>
|
||||||
This action will check-in account
|
This action will check-in account
|
||||||
{{this.selectedStatus.account}}
|
{{this.selectedStatus.account}}
|
||||||
back to the library. Do you want to proceed?
|
back to the library. Do you want to proceed?
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
type="button"
|
<Hds::Button
|
||||||
class="button is-primary {{if this.save.isRunning 'is-loading'}}"
|
@icon={{if this.save.isRunning "is-loading"}}
|
||||||
disabled={{this.checkIn.isRunning}}
|
disabled={{this.checkIn.isRunning}}
|
||||||
data-test-check-in-confirm
|
data-test-check-in-confirm
|
||||||
{{on "click" (perform this.checkIn)}}
|
{{on "click" (perform this.checkIn)}}
|
||||||
>
|
@text="Confirm"
|
||||||
Confirm
|
/>
|
||||||
</button>
|
<Hds::Button
|
||||||
<button
|
@icon={{if this.save.isRunning "is-loading"}}
|
||||||
type="button"
|
@color="secondary"
|
||||||
class="button"
|
|
||||||
disabled={{this.checkIn.isRunning}}
|
disabled={{this.checkIn.isRunning}}
|
||||||
{{on "click" (fn (mut this.selectedStatus) "")}}
|
{{on "click" (fn (mut this.selectedStatus) "")}}
|
||||||
>
|
@text="Cancel"
|
||||||
Cancel
|
/>
|
||||||
</button>
|
|
||||||
</footer>
|
</Hds::ButtonSet>
|
||||||
</Modal>
|
</M.Footer>
|
||||||
|
</Hds::Modal>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -78,14 +78,11 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
{{#if this.showRotatePrompt}}
|
{{#if this.showRotatePrompt}}
|
||||||
<Modal
|
<Hds::Modal id="ldap-rotate-password-modal" @onClose={{fn (mut this.showRotatePrompt) false}} as |M|>
|
||||||
@title="Rotate your root password?"
|
<M.Header @icon="info">
|
||||||
@type="info"
|
Rotate your root password?
|
||||||
@isActive={{this.showRotatePrompt}}
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
@onClose={{fn (mut this.showRotatePrompt) false}}
|
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p>
|
<p>
|
||||||
It’s best practice to rotate the administrator (root) password immediately after the initial configuration of the
|
It’s best practice to rotate the administrator (root) password immediately after the initial configuration of the
|
||||||
LDAP engine. The rotation will update the password both in Vault and your directory server. Once rotated,
|
LDAP engine. The rotation will update the password both in Vault and your directory server. Once rotated,
|
||||||
@@ -95,19 +92,17 @@
|
|||||||
<p>
|
<p>
|
||||||
Would you like to rotate your new credentials? You can also do this later.
|
Would you like to rotate your new credentials? You can also do this later.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
data-test-save-with-rotate
|
<Hds::Button data-test-save-with-rotate @text="Save and rotate" {{on "click" (fn (perform this.save) null true)}} />
|
||||||
type="button"
|
<Hds::Button
|
||||||
class="button is-primary"
|
data-test-save-without-rotate
|
||||||
{{on "click" (fn (perform this.save) null true)}}
|
@text="Save without rotating"
|
||||||
>
|
@color="secondary"
|
||||||
Save and rotate
|
{{on "click" (fn (perform this.save) null false)}}
|
||||||
</button>
|
/>
|
||||||
<button data-test-save-without-rotate type="button" class="button" {{on "click" (fn (perform this.save) null false)}}>
|
</Hds::ButtonSet>
|
||||||
Save without rotating
|
</M.Footer>
|
||||||
</button>
|
</Hds::Modal>
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -54,32 +54,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if this.showCheckOutPrompt}}
|
{{#if this.showCheckOutPrompt}}
|
||||||
<Modal
|
<Hds::Modal id="account-check-out-modal" @onClose={{fn (mut this.showCheckOutPrompt) false}} as |M|>
|
||||||
@title="Account Check-out"
|
<M.Header>
|
||||||
@isActive={{this.showCheckOutPrompt}}
|
Account Check-out
|
||||||
@showCloseButton={{true}}
|
</M.Header>
|
||||||
@onClose={{fn (mut this.showCheckOutPrompt) false}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<p>
|
<p>
|
||||||
Current generated credential’s time-to-live is set at
|
Current generated credential’s time-to-live is set at
|
||||||
{{format-duration @library.ttl}}. You can set a different limit if you’d like:
|
{{format-duration @library.ttl}}. You can set a different limit if you’d like:
|
||||||
</p>
|
</p>
|
||||||
<br />
|
<br />
|
||||||
<TtlPicker @label="TTL" @hideToggle={{true}} @initialValue={{@library.ttl}} @onChange={{this.setTtl}} />
|
<TtlPicker @label="TTL" @hideToggle={{true}} @initialValue={{@library.ttl}} @onChange={{this.setTtl}} />
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button data-test-check-out="save" type="button" class="button is-primary" {{on "click" this.checkOut}}>
|
<Hds::ButtonSet>
|
||||||
Check-out
|
<Hds::Button data-test-check-out="save" @text="Check-out" {{on "click" this.checkOut}} />
|
||||||
</button>
|
<Hds::Button data-test-check-out="cancel" @text="Cancel" @color="secondary" {{on "click" F.close}} />
|
||||||
<button
|
</Hds::ButtonSet>
|
||||||
data-test-check-out="cancel"
|
</M.Footer>
|
||||||
type="button"
|
</Hds::Modal>
|
||||||
class="button"
|
|
||||||
{{on "click" (fn (mut this.showCheckOutPrompt) false)}}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -111,19 +111,18 @@
|
|||||||
|
|
||||||
{{#if this.showDeleteAllIssuers}}
|
{{#if this.showDeleteAllIssuers}}
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
@title="Delete All Issuers?"
|
@title="Delete all issuers?"
|
||||||
@toConfirmMsg="deleting all issuers and keys."
|
@toConfirmMsg="deleting all issuers and keys."
|
||||||
@buttonText="Confirm"
|
|
||||||
@confirmText="delete-all"
|
@confirmText="delete-all"
|
||||||
@isActive={{this.showDeleteAllIssuers}}
|
@isActive={{this.showDeleteAllIssuers}}
|
||||||
@onClose={{action (mut this.showDeleteAllIssuers) false}}
|
@onClose={{action (mut this.showDeleteAllIssuers) false}}
|
||||||
@onConfirm={{this.deleteAllIssuers}}
|
@onConfirm={{this.deleteAllIssuers}}
|
||||||
>
|
>
|
||||||
<section class="modal-card-custom">
|
<p>
|
||||||
This endpoint deletes
|
This endpoint deletes
|
||||||
<strong>all</strong>
|
<strong>all</strong>
|
||||||
issuers and keys within the mount. It is highly recommended to use the individual delete operations instead. This mount
|
issuers and keys within the mount. It is highly recommended to use the individual delete operations instead. This mount
|
||||||
will be unusable until new issuers and keys are provisioned.
|
will be unusable until new issuers and keys are provisioned.
|
||||||
</section>
|
</p>
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -48,9 +48,9 @@
|
|||||||
@data={{@pem}}
|
@data={{@pem}}
|
||||||
@extension="pem"
|
@extension="pem"
|
||||||
data-test-issuer-download-type="pem"
|
data-test-issuer-download-type="pem"
|
||||||
>
|
@text="PEM format"
|
||||||
PEM format
|
@hideIcon={{true}}
|
||||||
</DownloadButton>
|
/>
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if @der}}
|
{{#if @der}}
|
||||||
@@ -62,9 +62,9 @@
|
|||||||
@data={{@der}}
|
@data={{@der}}
|
||||||
@extension="der"
|
@extension="der"
|
||||||
data-test-issuer-download-type="der"
|
data-test-issuer-download-type="der"
|
||||||
>
|
@text="DER format"
|
||||||
DER format
|
@hideIcon={{true}}
|
||||||
</DownloadButton>
|
/>
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</ul>
|
</ul>
|
||||||
@@ -148,14 +148,12 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{! ROOT ROTATION MODAL }}
|
{{! ROOT ROTATION MODAL }}
|
||||||
<Modal
|
{{#if this.showRotationModal}}
|
||||||
@type="rotation"
|
<Hds::Modal id="pki-rotate-root-modal" @size="large" @onClose={{fn (mut this.showRotationModal) false}} as |M|>
|
||||||
@title="Rotate this root"
|
<M.Header @icon="rotate-cw">
|
||||||
@onClose={{fn (mut this.showRotationModal) false}}
|
Rotate this root
|
||||||
@isActive={{this.showRotationModal}}
|
</M.Header>
|
||||||
@showCloseButton={{true}}
|
<M.Body>
|
||||||
>
|
|
||||||
<section class="modal-card-body">
|
|
||||||
<h3 class="title is-5">Root rotation</h3>
|
<h3 class="title is-5">Root rotation</h3>
|
||||||
<p class="has-text-grey has-bottom-padding-s">
|
<p class="has-text-grey has-bottom-padding-s">
|
||||||
Root rotation is an impactful process. Please be ready to ensure that the new root is properly distributed to
|
Root rotation is an impactful process. Please be ready to ensure that the new root is properly distributed to
|
||||||
@@ -175,18 +173,12 @@
|
|||||||
<div class="has-top-margin-l has-tall-padding">
|
<div class="has-top-margin-l has-tall-padding">
|
||||||
<img src={{img-path "~/pki-rotate-root.png"}} alt="pki root rotation diagram" />
|
<img src={{img-path "~/pki-rotate-root.png"}} alt="pki root rotation diagram" />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
type="button"
|
<Hds::Button @text="Generate new root" @route="issuers.issuer.rotate-root" data-test-root-rotate-step-one />
|
||||||
class="button is-primary"
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} />
|
||||||
{{on "click" (transition-to "vault.cluster.secrets.backend.pki.issuers.issuer.rotate-root")}}
|
</Hds::ButtonSet>
|
||||||
data-test-root-rotate-step-one
|
</M.Footer>
|
||||||
>
|
</Hds::Modal>
|
||||||
Generate new root
|
{{/if}}
|
||||||
</button>
|
|
||||||
<button type="button" class="button is-secondary" {{on "click" (fn (mut this.showRotationModal) false)}}>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
@@ -53,9 +53,9 @@
|
|||||||
@extension="pem"
|
@extension="pem"
|
||||||
@fetchData={{fn this.fetchDataForDownload "pem"}}
|
@fetchData={{fn this.fetchDataForDownload "pem"}}
|
||||||
data-test-issuer-download-type="pem"
|
data-test-issuer-download-type="pem"
|
||||||
>
|
@text="PEM format"
|
||||||
PEM format
|
@hideIcon={{true}}
|
||||||
</DownloadButton>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<li class="action">
|
<li class="action">
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
@@ -64,9 +64,9 @@
|
|||||||
@extension="der"
|
@extension="der"
|
||||||
@fetchData={{fn this.fetchDataForDownload "der"}}
|
@fetchData={{fn this.fetchDataForDownload "der"}}
|
||||||
data-test-issuer-download-type="der"
|
data-test-issuer-download-type="der"
|
||||||
>
|
@text="DER format"
|
||||||
DER format
|
@hideIcon={{true}}
|
||||||
</DownloadButton>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -19,14 +19,13 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if @key.privateKey}}
|
{{#if @key.privateKey}}
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
class="toolbar-link"
|
class="toolbar-button"
|
||||||
|
@color="secondary"
|
||||||
@filename="{{@key.backend}}-{{or @key.keyName 'private-key'}}"
|
@filename="{{@key.backend}}-{{or @key.keyName 'private-key'}}"
|
||||||
@data={{@key.privateKey}}
|
@data={{@key.privateKey}}
|
||||||
@extension="pem"
|
@extension="pem"
|
||||||
>
|
@text="Download private key"
|
||||||
Download private key
|
/>
|
||||||
<Chevron @isButton={{true}} />
|
|
||||||
</DownloadButton>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if @canEdit}}
|
{{#if @canEdit}}
|
||||||
<ToolbarLink @route="keys.key.edit" @model={{@key.keyId}} data-test-pki-key-edit>
|
<ToolbarLink @route="keys.key.edit" @model={{@key.keyId}} data-test-pki-key-edit>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<PkiPaginatedList @listRoute="keys.index" @list={{@keyModels}} @hasConfig={{@hasConfig}}>
|
<PkiPaginatedList @listRoute="keys.index" @list={{@keyModels}} @hasConfig={{@hasConfig}}>
|
||||||
<:actions>
|
<:actions>
|
||||||
{{#if @canImportKey}}
|
{{#if @canImportKey}}
|
||||||
<ToolbarLink @route="keys.import" @type="download" data-test-pki-key-import>
|
<ToolbarLink @route="keys.import" @type="upload" data-test-pki-key-import>
|
||||||
Import
|
Import
|
||||||
</ToolbarLink>
|
</ToolbarLink>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|||||||
@@ -14,15 +14,15 @@
|
|||||||
Perform manual tidy
|
Perform manual tidy
|
||||||
</ToolbarLink>
|
</ToolbarLink>
|
||||||
{{else}}
|
{{else}}
|
||||||
<button
|
<Hds::Button
|
||||||
type="button"
|
class="toolbar-button"
|
||||||
class="toolbar-link"
|
@color="secondary"
|
||||||
|
@icon="chevron-right"
|
||||||
|
@iconPosition="trailing"
|
||||||
{{on "click" (fn (mut this.tidyOptionsModal) true)}}
|
{{on "click" (fn (mut this.tidyOptionsModal) true)}}
|
||||||
data-test-pki-tidy-options-modal
|
data-test-pki-tidy-options-modal
|
||||||
>
|
@text="Tidy"
|
||||||
Tidy
|
/>
|
||||||
<Icon @name="chevron-right" />
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</ToolbarActions>
|
</ToolbarActions>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
@@ -101,25 +101,24 @@
|
|||||||
@title="Tidy status unavailable"
|
@title="Tidy status unavailable"
|
||||||
@message="After the next tidy operation has been performed, information about the current or most recent tidy operation will display here."
|
@message="After the next tidy operation has been performed, information about the current or most recent tidy operation will display here."
|
||||||
>
|
>
|
||||||
<button
|
<Hds::Button
|
||||||
type="button"
|
@color="tertiary"
|
||||||
class="link"
|
@icon="chevron-right"
|
||||||
|
@iconPosition="trailing"
|
||||||
{{on "click" (fn (mut this.tidyOptionsModal) true)}}
|
{{on "click" (fn (mut this.tidyOptionsModal) true)}}
|
||||||
data-test-tidy-empty-state-configure
|
data-test-tidy-empty-state-configure
|
||||||
>
|
@text="Tidy"
|
||||||
Tidy
|
/>
|
||||||
</button>
|
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{! TIDY OPTIONS MODAL }}
|
{{! TIDY OPTIONS MODAL }}
|
||||||
<Modal
|
{{#if this.tidyOptionsModal}}
|
||||||
@title="Tidy this mount"
|
<Hds::Modal id="pki-tidy-modal" @size="large" @onClose={{fn (mut this.tidyOptionsModal) false}} as |M|>
|
||||||
@onClose={{fn (mut this.tidyOptionsModal) false}}
|
<M.Header>
|
||||||
@isActive={{this.tidyOptionsModal}}
|
Tidy this mount
|
||||||
@showCloseButton={{true}}
|
</M.Header>
|
||||||
>
|
<M.Body>
|
||||||
<section aria-label="tidy-options-modal-content" class="modal-card-body">
|
|
||||||
<h3 class="title is-5">How tidying will work</h3>
|
<h3 class="title is-5">How tidying will work</h3>
|
||||||
<p class="has-text-grey has-bottom-padding-s">
|
<p class="has-text-grey has-bottom-padding-s">
|
||||||
Tidying cleans up the storage backend and/or CRL by removing certificates that have expired and are past a certain
|
Tidying cleans up the storage backend and/or CRL by removing certificates that have expired and are past a certain
|
||||||
@@ -144,61 +143,33 @@
|
|||||||
<div class="has-top-margin-l has-padding">
|
<div class="has-top-margin-l has-padding">
|
||||||
<img src={{img-path "~/pki-tidy.png"}} alt="tidy operation diagram" />
|
<img src={{img-path "~/pki-tidy.png"}} alt="tidy operation diagram" />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer aria-label="tidy-option-buttons" class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
type="button"
|
<Hds::Button @text="Automatic tidy" @route="tidy.auto.configure" data-test-tidy-modal-auto-button />
|
||||||
class="button is-primary"
|
<Hds::Button @text="Manual tidy" @route="tidy.manual" data-test-tidy-modal-manual-button />
|
||||||
{{on "click" (transition-to "vault.cluster.secrets.backend.pki.tidy.auto.configure")}}
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} data-test-tidy-modal-cancel-button />
|
||||||
data-test-tidy-modal-auto-button
|
</Hds::ButtonSet>
|
||||||
>
|
</M.Footer>
|
||||||
Automatic tidy
|
</Hds::Modal>
|
||||||
</button>
|
{{/if}}
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="button is-primary"
|
|
||||||
{{on "click" (transition-to "vault.cluster.secrets.backend.pki.tidy.manual")}}
|
|
||||||
data-test-tidy-modal-manual-button
|
|
||||||
>
|
|
||||||
Manual tidy
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="button is-secondary"
|
|
||||||
{{on "click" (fn (mut this.tidyOptionsModal) false)}}
|
|
||||||
data-test-tidy-modal-cancel-button
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
{{! CANCEL TIDY CONFIRMATION MODAL }}
|
{{! CANCEL TIDY CONFIRMATION MODAL }}
|
||||||
{{#if this.confirmCancelTidy}}
|
{{#if this.confirmCancelTidy}}
|
||||||
<Modal
|
<Hds::Modal id="pki-cancel-tidy-modal" @color="warning" @onClose={{fn (mut this.confirmCancelTidy) false}} as |M|>
|
||||||
@type="warning"
|
<M.Header @icon="alert-triangle">
|
||||||
@title="Cancel tidy?"
|
Cancel tidy?
|
||||||
@onClose={{fn (mut this.confirmCancelTidy) false}}
|
</M.Header>
|
||||||
@isActive={{this.confirmCancelTidy}}
|
<M.Body>
|
||||||
@showCloseButton={{true}}
|
|
||||||
>
|
|
||||||
<section aria-label="confirm-cancel-modal-content" class="modal-card-body">
|
|
||||||
This will cancel the tidy at the next available checkpoint, which may process additional certificates between when the
|
This will cancel the tidy at the next available checkpoint, which may process additional certificates between when the
|
||||||
operation was marked as cancelled and when the operation stopped.
|
operation was marked as cancelled and when the operation stopped.
|
||||||
<p class="has-top-margin-s">Click “Confirm” to cancel the running tidy operation.</p>
|
<p class="has-top-margin-s">Click “Confirm” to cancel the running tidy operation.</p>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer aria-label="confirm-cancel-buttons" class="modal-card-foot modal-card-foot-outlined">
|
<M.Footer as |F|>
|
||||||
<button
|
<Hds::ButtonSet>
|
||||||
type="button"
|
<Hds::Button @text="Confirm" {{on "click" (perform this.cancelTidy)}} data-test-tidy-modal-cancel-button />
|
||||||
class="button is-primary"
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} />
|
||||||
{{on "click" (perform this.cancelTidy)}}
|
</Hds::ButtonSet>
|
||||||
data-test-tidy-modal-cancel-button
|
</M.Footer>
|
||||||
>
|
</Hds::Modal>
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
<button type="button" class="button is-secondary" {{on "click" (fn (mut this.confirmCancelTidy) false)}}>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</Modal>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -26,11 +26,11 @@ const DEFAULTS = {
|
|||||||
|
|
||||||
export default Controller.extend(copy(DEFAULTS, true), {
|
export default Controller.extend(copy(DEFAULTS, true), {
|
||||||
isModalActive: false,
|
isModalActive: false,
|
||||||
|
isTokenCopied: false,
|
||||||
expirationDate: null,
|
expirationDate: null,
|
||||||
store: service(),
|
store: service(),
|
||||||
rm: service('replication-mode'),
|
rm: service('replication-mode'),
|
||||||
replicationMode: alias('rm.mode'),
|
replicationMode: alias('rm.mode'),
|
||||||
flashMessages: service(),
|
|
||||||
|
|
||||||
submitError(e) {
|
submitError(e) {
|
||||||
if (e.errors) {
|
if (e.errors) {
|
||||||
@@ -121,25 +121,13 @@ export default Controller.extend(copy(DEFAULTS, true), {
|
|||||||
onSubmit(/*action, mode, data, event*/) {
|
onSubmit(/*action, mode, data, event*/) {
|
||||||
return this.submitHandler(...arguments);
|
return this.submitHandler(...arguments);
|
||||||
},
|
},
|
||||||
copyClose(successMessage) {
|
closeTokenModal() {
|
||||||
// separate action for copy & close button so it does not try and use execCommand to copy token to clipboard
|
|
||||||
if (!!successMessage && typeof successMessage === 'string') {
|
|
||||||
this.flashMessages.success(successMessage);
|
|
||||||
}
|
|
||||||
this.toggleProperty('isModalActive');
|
this.toggleProperty('isModalActive');
|
||||||
this.transitionToRoute('mode.secondaries');
|
this.transitionToRoute('mode.secondaries');
|
||||||
|
this.set('isTokenCopied', false);
|
||||||
},
|
},
|
||||||
toggleModal(successMessage) {
|
onCopy() {
|
||||||
if (!!successMessage && typeof successMessage === 'string') {
|
this.set('isTokenCopied', true);
|
||||||
this.flashMessages.success(successMessage);
|
|
||||||
}
|
|
||||||
// use copy browser extension to copy token if you close the modal by clicking outside of it.
|
|
||||||
const htmlSelectedToken = document.querySelector('#token-textarea');
|
|
||||||
htmlSelectedToken.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
|
|
||||||
this.toggleProperty('isModalActive');
|
|
||||||
this.transitionToRoute('mode.secondaries');
|
|
||||||
},
|
},
|
||||||
clear() {
|
clear() {
|
||||||
this.reset();
|
this.reset();
|
||||||
|
|||||||
@@ -60,8 +60,16 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
{{#if this.isModalActive}}
|
{{#if this.isModalActive}}
|
||||||
<Modal @title="Copy your token" @onClose={{action "toggleModal" "Token copied!"}} @isActive={{this.isModalActive}}>
|
<Hds::Modal
|
||||||
<section class="modal-card-body">
|
id="replication-copy-token-modal"
|
||||||
|
@onClose={{action "closeTokenModal"}}
|
||||||
|
@isDismissDisabled={{not this.isTokenCopied}}
|
||||||
|
as |M|
|
||||||
|
>
|
||||||
|
<M.Header>
|
||||||
|
Copy your token
|
||||||
|
</M.Header>
|
||||||
|
<M.Body>
|
||||||
<p>
|
<p>
|
||||||
This token can be used to enable
|
This token can be used to enable
|
||||||
{{this.model.replicationModeForDisplay}}
|
{{this.model.replicationModeForDisplay}}
|
||||||
@@ -79,14 +87,28 @@
|
|||||||
<InfoTableRow @label="Expires" @value={{date-format this.expirationDate "MMM dd, yyyy hh:mm:ss a"}} />
|
<InfoTableRow @label="Expires" @value={{date-format this.expirationDate "MMM dd, yyyy hh:mm:ss a"}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</M.Body>
|
||||||
<footer class="modal-card-foot">
|
<M.Footer>
|
||||||
|
<Hds::ButtonSet>
|
||||||
<Hds::Copy::Button
|
<Hds::Copy::Button
|
||||||
@text="Copy & Close"
|
data-test-modal-copy
|
||||||
|
@text="Copy token"
|
||||||
@textToCopy={{this.token}}
|
@textToCopy={{this.token}}
|
||||||
class="primary"
|
class="primary"
|
||||||
{{on "click" (action "copyClose" "Token copied!")}}
|
@container=".hds-modal"
|
||||||
|
{{on "click" (action "onCopy")}}
|
||||||
/>
|
/>
|
||||||
</footer>
|
<Hds::Button
|
||||||
</Modal>
|
data-test-modal-close
|
||||||
|
disabled={{not this.isTokenCopied}}
|
||||||
|
@text="Close"
|
||||||
|
@color="secondary"
|
||||||
|
{{on "click" (action "closeTokenModal")}}
|
||||||
|
/>
|
||||||
|
{{#unless this.isTokenCopied}}
|
||||||
|
<AlertInline @type="warning" @message="Copy token to dismiss modal" />
|
||||||
|
{{/unless}}
|
||||||
|
</Hds::ButtonSet>
|
||||||
|
</M.Footer>
|
||||||
|
</Hds::Modal>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -65,7 +65,6 @@
|
|||||||
"@ember/test-waiters": "^3.0.0",
|
"@ember/test-waiters": "^3.0.0",
|
||||||
"@glimmer/component": "^1.1.2",
|
"@glimmer/component": "^1.1.2",
|
||||||
"@glimmer/tracking": "^1.1.2",
|
"@glimmer/tracking": "^1.1.2",
|
||||||
"@hashicorp/ember-flight-icons": "^3.0.9",
|
|
||||||
"@hashicorp/structure-icons": "^1.3.0",
|
"@hashicorp/structure-icons": "^1.3.0",
|
||||||
"@icholy/duration": "^5.1.0",
|
"@icholy/duration": "^5.1.0",
|
||||||
"@tsconfig/ember": "^1.0.1",
|
"@tsconfig/ember": "^1.0.1",
|
||||||
@@ -166,7 +165,6 @@
|
|||||||
"ember-test-selectors": "6.0.0",
|
"ember-test-selectors": "6.0.0",
|
||||||
"ember-tether": "^2.0.1",
|
"ember-tether": "^2.0.1",
|
||||||
"ember-truth-helpers": "3.0.0",
|
"ember-truth-helpers": "3.0.0",
|
||||||
"ember-wormhole": "0.6.0",
|
|
||||||
"escape-string-regexp": "^2.0.0",
|
"escape-string-regexp": "^2.0.0",
|
||||||
"eslint": "^8.37.0",
|
"eslint": "^8.37.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
@@ -248,7 +246,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hashicorp/design-system-components": "^2.9.0",
|
"@hashicorp/design-system-components": "^2.12.2",
|
||||||
|
"@hashicorp/ember-flight-icons": "^3.1.3",
|
||||||
"handlebars": "4.7.7",
|
"handlebars": "4.7.7",
|
||||||
"highlight.js": "^10.4.1",
|
"highlight.js": "^10.4.1",
|
||||||
"node-notifier": "^8.0.1",
|
"node-notifier": "^8.0.1",
|
||||||
|
|||||||
@@ -390,9 +390,9 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||||||
.dom(SELECTORS.emptyStateTitle)
|
.dom(SELECTORS.emptyStateTitle)
|
||||||
.includesText('start date found', 'Empty state shows no billing start date');
|
.includesText('start date found', 'Empty state shows no billing start date');
|
||||||
await click(SELECTORS.monthDropdown);
|
await click(SELECTORS.monthDropdown);
|
||||||
await click(this.element.querySelector('[data-test-month-list] button:not([disabled])'));
|
await click(this.element.querySelector('[data-test-dropdown-month]:not([disabled])'));
|
||||||
await click(SELECTORS.yearDropdown);
|
await click(SELECTORS.yearDropdown);
|
||||||
await click(this.element.querySelector('[data-test-year-list] button:not([disabled])'));
|
await click(this.element.querySelector('[data-test-dropdown-year]:not([disabled])'));
|
||||||
await click(SELECTORS.dateDropdownSubmit);
|
await click(SELECTORS.dateDropdownSubmit);
|
||||||
assert
|
assert
|
||||||
.dom(SELECTORS.emptyStateTitle)
|
.dom(SELECTORS.emptyStateTitle)
|
||||||
|
|||||||
@@ -250,11 +250,16 @@ module('Acceptance | Enterprise | replication', function (hooks) {
|
|||||||
await pollCluster(this.owner);
|
await pollCluster(this.owner);
|
||||||
await settled();
|
await settled();
|
||||||
const modalDefaultTtl = document.querySelector('[data-test-row-value="TTL"]').innerText;
|
const modalDefaultTtl = document.querySelector('[data-test-row-value="TTL"]').innerText;
|
||||||
|
|
||||||
// checks on secondary token modal
|
// checks on secondary token modal
|
||||||
assert.dom('#modal-wormhole').exists();
|
assert.dom('.hds-modal#replication-copy-token-modal').exists();
|
||||||
|
assert.dom('[data-test-inline-error-message]').hasText('Copy token to dismiss modal');
|
||||||
assert.strictEqual(modalDefaultTtl, '1800s', 'shows the correct TTL of 1800s');
|
assert.strictEqual(modalDefaultTtl, '1800s', 'shows the correct TTL of 1800s');
|
||||||
// click off the modal to make sure you don't just have to click on the copy-close button to copy the token
|
// click off the modal to make sure you don't just have to click on the copy-close button to copy the token
|
||||||
await click('[data-test-modal-background="Copy your token"]');
|
assert.dom('[data-test-modal-close]').isDisabled('cancel is disabled');
|
||||||
|
await click('[data-test-modal-copy]');
|
||||||
|
assert.dom('[data-test-modal-close]').isEnabled('cancel is enabled after token is copied');
|
||||||
|
await click('[data-test-modal-close]');
|
||||||
|
|
||||||
// add another secondary not using the default ttl
|
// add another secondary not using the default ttl
|
||||||
await click('[data-test-secondary-add]');
|
await click('[data-test-secondary-add]');
|
||||||
@@ -269,7 +274,8 @@ module('Acceptance | Enterprise | replication', function (hooks) {
|
|||||||
await settled();
|
await settled();
|
||||||
const modalTtl = document.querySelector('[data-test-row-value="TTL"]').innerText;
|
const modalTtl = document.querySelector('[data-test-row-value="TTL"]').innerText;
|
||||||
assert.strictEqual(modalTtl, '180s', 'shows the correct TTL of 180s');
|
assert.strictEqual(modalTtl, '180s', 'shows the correct TTL of 180s');
|
||||||
await click('[data-test-modal-background="Copy your token"]');
|
await click('[data-test-modal-copy]');
|
||||||
|
await click('[data-test-modal-close]');
|
||||||
|
|
||||||
// confirm you were redirected to the secondaries page
|
// confirm you were redirected to the secondaries page
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
|
|||||||
@@ -432,7 +432,7 @@ module('Acceptance | pki workflow', function (hooks) {
|
|||||||
.dom(SELECTORS.issuerDetails.configure)
|
.dom(SELECTORS.issuerDetails.configure)
|
||||||
.hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/edit`);
|
.hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/edit`);
|
||||||
await click(SELECTORS.issuerDetails.rotateRoot);
|
await click(SELECTORS.issuerDetails.rotateRoot);
|
||||||
assert.dom(find(SELECTORS.issuerDetails.rotateModal).parentElement).hasClass('is-active');
|
assert.dom(SELECTORS.issuerDetails.rotateModal).exists('rotate root modal opens');
|
||||||
await click(SELECTORS.issuerDetails.rotateModalGenerate);
|
await click(SELECTORS.issuerDetails.rotateModalGenerate);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
currentURL(),
|
currentURL(),
|
||||||
|
|||||||
@@ -163,7 +163,6 @@ module('Acceptance | pki tidy', function (hooks) {
|
|||||||
.exists('Configure tidy modal options button exists');
|
.exists('Configure tidy modal options button exists');
|
||||||
await click(SELECTORS.tidyConfigureModal.tidyOptionsModal);
|
await click(SELECTORS.tidyConfigureModal.tidyOptionsModal);
|
||||||
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
|
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
|
||||||
await click(SELECTORS.tidyConfigureModal.tidyOptionsModal);
|
|
||||||
await click(SELECTORS.tidyConfigureModal.tidyModalAutoButton);
|
await click(SELECTORS.tidyConfigureModal.tidyModalAutoButton);
|
||||||
await click(SELECTORS.tidyForm.toggleLabel('Automatic tidy disabled'));
|
await click(SELECTORS.tidyForm.toggleLabel('Automatic tidy disabled'));
|
||||||
await click(SELECTORS.tidyForm.inputByAttr('tidyCertStore'));
|
await click(SELECTORS.tidyForm.inputByAttr('tidyCertStore'));
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ module('Acceptance | secrets/database/*', function (hooks) {
|
|||||||
await connectionPage.save();
|
await connectionPage.save();
|
||||||
await settled();
|
await settled();
|
||||||
assert
|
assert
|
||||||
.dom('.modal.is-active .title')
|
.dom('[data-test-db-connection-modal-title]')
|
||||||
.hasText('Rotate your root credentials?', 'Modal appears asking to rotate root credentials');
|
.hasText('Rotate your root credentials?', 'Modal appears asking to rotate root credentials');
|
||||||
assert.dom('[data-test-enable-connection]').exists('Enable button exists');
|
assert.dom('[data-test-enable-connection]').exists('Enable button exists');
|
||||||
await click('[data-test-enable-connection]');
|
await click('[data-test-enable-connection]');
|
||||||
@@ -397,7 +397,7 @@ module('Acceptance | secrets/database/*', function (hooks) {
|
|||||||
await connectionPage.save();
|
await connectionPage.save();
|
||||||
await settled();
|
await settled();
|
||||||
assert
|
assert
|
||||||
.dom('.modal.is-active .title')
|
.dom('[data-test-db-connection-modal-title]')
|
||||||
.hasText('Rotate your root credentials?', 'Modal appears asking to ');
|
.hasText('Rotate your root credentials?', 'Modal appears asking to ');
|
||||||
await connectionPage.enable();
|
await connectionPage.enable();
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@@ -418,7 +418,7 @@ module('Acceptance | secrets/database/*', function (hooks) {
|
|||||||
});
|
});
|
||||||
await connectionPage.delete();
|
await connectionPage.delete();
|
||||||
assert
|
assert
|
||||||
.dom('.modal.is-active .title')
|
.dom('[data-test-confirmation-modal-title]')
|
||||||
.hasText('Delete connection?', 'Modal appears asking to confirm delete action');
|
.hasText('Delete connection?', 'Modal appears asking to confirm delete action');
|
||||||
await fillIn('[data-test-confirmation-modal-input="Delete connection?"]', connectionDetails.id);
|
await fillIn('[data-test-confirmation-modal-input="Delete connection?"]', connectionDetails.id);
|
||||||
await click('[data-test-confirm-button]');
|
await click('[data-test-confirm-button]');
|
||||||
|
|||||||
@@ -37,14 +37,14 @@ const testConvergentEncryption = async function (assert, keyName) {
|
|||||||
encodePlaintext: false,
|
encodePlaintext: false,
|
||||||
encodeContext: false,
|
encodeContext: false,
|
||||||
assertAfterEncrypt: (key) => {
|
assertAfterEncrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').exists(`${key}: Modal opens after encrypt`);
|
assert.dom('[data-test-encrypt-modal]').exists(`${key}: Modal opens after encrypt`);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
/vault:/.test(find('[data-test-encrypted-value="ciphertext"]').innerText),
|
/vault:/.test(find('[data-test-encrypted-value="ciphertext"]').innerText),
|
||||||
`${key}: ciphertext shows a vault-prefixed ciphertext`
|
`${key}: ciphertext shows a vault-prefixed ciphertext`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
assertBeforeDecrypt: (key) => {
|
assertBeforeDecrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').doesNotExist(`${key}: Modal not open before decrypt`);
|
assert.dom('[data-test-decrypt-modal]').doesNotExist(`${key}: Modal not open before decrypt`);
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-transit-input="context"]')
|
.dom('[data-test-transit-input="context"]')
|
||||||
.hasValue(
|
.hasValue(
|
||||||
@@ -52,9 +52,8 @@ const testConvergentEncryption = async function (assert, keyName) {
|
|||||||
`${key}: the ui shows the base64-encoded context`
|
`${key}: the ui shows the base64-encoded context`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
assertAfterDecrypt: (key) => {
|
assertAfterDecrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').exists(`${key}: Modal opens after decrypt`);
|
assert.dom('[data-test-decrypt-modal]').exists(`${key}: Modal opens after decrypt`);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
find('[data-test-encrypted-value="plaintext"]').innerText,
|
find('[data-test-encrypted-value="plaintext"]').innerText,
|
||||||
'NaXud2QW7KjyK6Me9ggh+zmnCeBGdG93LQED49PtoOI=',
|
'NaXud2QW7KjyK6Me9ggh+zmnCeBGdG93LQED49PtoOI=',
|
||||||
@@ -69,20 +68,20 @@ const testConvergentEncryption = async function (assert, keyName) {
|
|||||||
encodePlaintext: false,
|
encodePlaintext: false,
|
||||||
encodeContext: false,
|
encodeContext: false,
|
||||||
assertAfterEncrypt: (key) => {
|
assertAfterEncrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').exists(`${key}: Modal opens after encrypt`);
|
assert.dom('[data-test-encrypt-modal]').exists(`${key}: Modal opens after encrypt`);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
/vault:/.test(find('[data-test-encrypted-value="ciphertext"]').innerText),
|
/vault:/.test(find('[data-test-encrypted-value="ciphertext"]').innerText),
|
||||||
`${key}: ciphertext shows a vault-prefixed ciphertext`
|
`${key}: ciphertext shows a vault-prefixed ciphertext`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
assertBeforeDecrypt: (key) => {
|
assertBeforeDecrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').doesNotExist(`${key}: Modal not open before decrypt`);
|
assert.dom('[data-test-decrypt-modal]').doesNotExist(`${key}: Modal not open before decrypt`);
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-transit-input="context"]')
|
.dom('[data-test-transit-input="context"]')
|
||||||
.hasValue(encodeString('context'), `${key}: the ui shows the input context`);
|
.hasValue(encodeString('context'), `${key}: the ui shows the input context`);
|
||||||
},
|
},
|
||||||
assertAfterDecrypt: (key) => {
|
assertAfterDecrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').exists(`${key}: Modal opens after decrypt`);
|
assert.dom('[data-test-decrypt-modal]').exists(`${key}: Modal opens after decrypt`);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
find('[data-test-encrypted-value="plaintext"]').innerText,
|
find('[data-test-encrypted-value="plaintext"]').innerText,
|
||||||
'NaXud2QW7KjyK6Me9ggh+zmnCeBGdG93LQED49PtoOI=',
|
'NaXud2QW7KjyK6Me9ggh+zmnCeBGdG93LQED49PtoOI=',
|
||||||
@@ -97,20 +96,20 @@ const testConvergentEncryption = async function (assert, keyName) {
|
|||||||
encodePlaintext: false,
|
encodePlaintext: false,
|
||||||
encodeContext: false,
|
encodeContext: false,
|
||||||
assertAfterEncrypt: (key) => {
|
assertAfterEncrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').exists(`${key}: Modal opens after encrypt`);
|
assert.dom('[data-test-encrypt-modal]').exists(`${key}: Modal opens after encrypt`);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
/vault:/.test(find('[data-test-encrypted-value="ciphertext"]').innerText),
|
/vault:/.test(find('[data-test-encrypted-value="ciphertext"]').innerText),
|
||||||
`${key}: ciphertext shows a vault-prefixed ciphertext`
|
`${key}: ciphertext shows a vault-prefixed ciphertext`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
assertBeforeDecrypt: (key) => {
|
assertBeforeDecrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').doesNotExist(`${key}: Modal not open before decrypt`);
|
assert.dom('[data-test-decrypt-modal]').doesNotExist(`${key}: Modal not open before decrypt`);
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-transit-input="context"]')
|
.dom('[data-test-transit-input="context"]')
|
||||||
.hasValue(encodeString('context'), `${key}: the ui shows the input context`);
|
.hasValue(encodeString('context'), `${key}: the ui shows the input context`);
|
||||||
},
|
},
|
||||||
assertAfterDecrypt: (key) => {
|
assertAfterDecrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').exists(`${key}: Modal opens after decrypt`);
|
assert.dom('[data-test-decrypt-modal]').exists(`${key}: Modal opens after decrypt`);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
find('[data-test-encrypted-value="plaintext"]').innerText,
|
find('[data-test-encrypted-value="plaintext"]').innerText,
|
||||||
encodeString('This is the secret'),
|
encodeString('This is the secret'),
|
||||||
@@ -125,20 +124,20 @@ const testConvergentEncryption = async function (assert, keyName) {
|
|||||||
encodePlaintext: true,
|
encodePlaintext: true,
|
||||||
encodeContext: true,
|
encodeContext: true,
|
||||||
assertAfterEncrypt: (key) => {
|
assertAfterEncrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').exists(`${key}: Modal opens after encrypt`);
|
assert.dom('[data-test-encrypt-modal]').exists(`${key}: Modal opens after encrypt`);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
/vault:/.test(find('[data-test-encrypted-value="ciphertext"]').innerText),
|
/vault:/.test(find('[data-test-encrypted-value="ciphertext"]').innerText),
|
||||||
`${key}: ciphertext shows a vault-prefixed ciphertext`
|
`${key}: ciphertext shows a vault-prefixed ciphertext`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
assertBeforeDecrypt: (key) => {
|
assertBeforeDecrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').doesNotExist(`${key}: Modal not open before decrypt`);
|
assert.dom('[data-test-decrypt-modal]').doesNotExist(`${key}: Modal not open before decrypt`);
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-transit-input="context"]')
|
.dom('[data-test-transit-input="context"]')
|
||||||
.hasValue(encodeString('secret 2'), `${key}: the ui shows the encoded context`);
|
.hasValue(encodeString('secret 2'), `${key}: the ui shows the encoded context`);
|
||||||
},
|
},
|
||||||
assertAfterDecrypt: (key) => {
|
assertAfterDecrypt: (key) => {
|
||||||
assert.dom('.modal.is-active').exists(`${key}: Modal opens after decrypt`);
|
assert.dom('[data-test-decrypt-modal]').exists(`${key}: Modal opens after decrypt`);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
find('[data-test-encrypted-value="plaintext"]').innerText,
|
find('[data-test-encrypted-value="plaintext"]').innerText,
|
||||||
encodeString('There are many secrets 🤐'),
|
encodeString('There are many secrets 🤐'),
|
||||||
@@ -161,7 +160,7 @@ const testConvergentEncryption = async function (assert, keyName) {
|
|||||||
if (testCase.encodeContext) {
|
if (testCase.encodeContext) {
|
||||||
await click('[data-test-transit-b64-toggle="context"]');
|
await click('[data-test-transit-b64-toggle="context"]');
|
||||||
}
|
}
|
||||||
assert.dom('.modal.is-active').doesNotExist(`${name}: is not open before encrypt`);
|
assert.dom('[data-test-encrypt-modal]').doesNotExist(`${name}: is not open before encrypt`);
|
||||||
await click('[data-test-button-encrypt]');
|
await click('[data-test-button-encrypt]');
|
||||||
|
|
||||||
if (testCase.assertAfterEncrypt) {
|
if (testCase.assertAfterEncrypt) {
|
||||||
@@ -170,9 +169,9 @@ const testConvergentEncryption = async function (assert, keyName) {
|
|||||||
}
|
}
|
||||||
// store ciphertext for decryption step
|
// store ciphertext for decryption step
|
||||||
const copiedCiphertext = find('[data-test-encrypted-value="ciphertext"]').innerText;
|
const copiedCiphertext = find('[data-test-encrypted-value="ciphertext"]').innerText;
|
||||||
await click('.modal.is-active [data-test-modal-background]');
|
await click('dialog button');
|
||||||
|
|
||||||
assert.dom('.modal.is-active').doesNotExist(`${name}: Modal closes after background clicked`);
|
assert.dom('dialog.hds-modal').doesNotExist(`${name}: Modal closes after background clicked`);
|
||||||
await click('[data-test-transit-action-link="decrypt"]');
|
await click('[data-test-transit-action-link="decrypt"]');
|
||||||
|
|
||||||
if (testCase.assertBeforeDecrypt) {
|
if (testCase.assertBeforeDecrypt) {
|
||||||
@@ -187,9 +186,9 @@ const testConvergentEncryption = async function (assert, keyName) {
|
|||||||
testCase.assertAfterDecrypt(keyName);
|
testCase.assertAfterDecrypt(keyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
await click('.modal.is-active [data-test-modal-background]');
|
await click('dialog button');
|
||||||
|
|
||||||
assert.dom('.modal.is-active').doesNotExist(`${name}: Modal closes after background clicked`);
|
assert.dom('dialog.hds-modal').doesNotExist(`${name}: Modal closes after background clicked`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ export const SELECTORS = {
|
|||||||
attributionBlock: '[data-test-clients-attribution]',
|
attributionBlock: '[data-test-clients-attribution]',
|
||||||
filterBar: '[data-test-clients-filter-bar]',
|
filterBar: '[data-test-clients-filter-bar]',
|
||||||
rangeDropdown: '[data-test-calendar-widget-trigger]',
|
rangeDropdown: '[data-test-calendar-widget-trigger]',
|
||||||
monthDropdown: '[data-test-popup-menu-trigger="month"]',
|
monthDropdown: '[data-test-toggle-month]',
|
||||||
yearDropdown: '[data-test-popup-menu-trigger="year"]',
|
yearDropdown: '[data-test-toggle-year]',
|
||||||
dateDropdownSubmit: '[data-test-date-dropdown-submit]',
|
dateDropdownSubmit: '[data-test-date-dropdown-submit]',
|
||||||
runningTotalMonthStats: '[data-test-running-total="single-month-stats"]',
|
runningTotalMonthStats: '[data-test-running-total="single-month-stats"]',
|
||||||
runningTotalMonthlyCharts: '[data-test-running-total="monthly-charts"]',
|
runningTotalMonthlyCharts: '[data-test-running-total="monthly-charts"]',
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export const PAGE = {
|
|||||||
message: '[data-test-page-error] p',
|
message: '[data-test-page-error] p',
|
||||||
},
|
},
|
||||||
toolbar: 'nav.toolbar',
|
toolbar: 'nav.toolbar',
|
||||||
toolbarAction: 'nav.toolbar-actions .toolbar-link',
|
toolbarAction: 'nav.toolbar-actions .toolbar-link, nav.toolbar-actions .toolbar-button',
|
||||||
secretRow: '[data-test-component="info-table-row"]', // replace with infoRow
|
secretRow: '[data-test-component="info-table-row"]', // replace with infoRow
|
||||||
// specific page selectors
|
// specific page selectors
|
||||||
backends: {
|
backends: {
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ export const SELECTORS = {
|
|||||||
hdsAlertButtonText: '[data-test-cancel-tidy-action] .hds-button__text',
|
hdsAlertButtonText: '[data-test-cancel-tidy-action] .hds-button__text',
|
||||||
timeStartedRow: '[data-test-value-div="Time started"]',
|
timeStartedRow: '[data-test-value-div="Time started"]',
|
||||||
timeFinishedRow: '[data-test-value-div="Time finished"]',
|
timeFinishedRow: '[data-test-value-div="Time finished"]',
|
||||||
cancelTidyModalBackground: '[data-test-modal-background="Cancel tidy?"]',
|
cancelTidyModalBackground: '.hds-modal#pki-cancel-tidy-modal',
|
||||||
tidyEmptyStateConfigure: '[data-test-tidy-empty-state-configure]',
|
tidyEmptyStateConfigure: '[data-test-tidy-empty-state-configure]',
|
||||||
manualTidyToolbar: '[data-test-pki-manual-tidy-config]',
|
manualTidyToolbar: '[data-test-pki-manual-tidy-config]',
|
||||||
autoTidyToolbar: '[data-test-pki-auto-tidy-config]',
|
autoTidyToolbar: '[data-test-pki-auto-tidy-config]',
|
||||||
tidyConfigureModal: {
|
tidyConfigureModal: {
|
||||||
configureTidyModal: '[data-test-modal-background="Tidy this mount"]',
|
configureTidyModal: '.hds-modal#pki-tidy-modal',
|
||||||
tidyModalAutoButton: '[data-test-tidy-modal-auto-button]',
|
tidyModalAutoButton: '[data-test-tidy-modal-auto-button]',
|
||||||
tidyModalManualButton: '[data-test-tidy-modal-manual-button]',
|
tidyModalManualButton: '[data-test-tidy-modal-manual-button]',
|
||||||
tidyModalCancelButton: '[data-test-tidy-modal-cancel-button]',
|
tidyModalCancelButton: '[data-test-tidy-modal-cancel-button]',
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
export const SELECTORS = {
|
export const SELECTORS = {
|
||||||
issuerLink: '[data-test-delete-all-issuers-link]',
|
issuerLink: '[data-test-delete-all-issuers-link]',
|
||||||
deleteAllIssuerModal: '[data-test-modal-background="Delete All Issuers?"]',
|
deleteAllIssuerModal: '.hds-modal#confirmation-modal',
|
||||||
deleteAllIssuerInput: '[data-test-confirmation-modal-input="Delete All Issuers?"]',
|
deleteAllIssuerInput: '[data-test-confirmation-modal-input="Delete all issuers?"]',
|
||||||
deleteAllIssuerButton: '[data-test-confirm-button="Delete All Issuers?"]',
|
deleteAllIssuerButton: '[data-test-confirm-button="Delete all issuers?"]',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const SELECTORS = {
|
|||||||
download: '[data-test-issuer-download]',
|
download: '[data-test-issuer-download]',
|
||||||
groupTitle: '[data-test-group-title]',
|
groupTitle: '[data-test-group-title]',
|
||||||
parsingAlertBanner: '[data-test-parsing-error-alert-banner]',
|
parsingAlertBanner: '[data-test-parsing-error-alert-banner]',
|
||||||
rotateModal: '[data-test-modal-background="Rotate this root"]',
|
rotateModal: '.hds-modal#pki-rotate-root-modal',
|
||||||
rotateModalGenerate: '[data-test-root-rotate-step-one]',
|
rotateModalGenerate: '[data-test-root-rotate-step-one]',
|
||||||
rotateRoot: '[data-test-pki-issuer-rotate-root]',
|
rotateRoot: '[data-test-pki-issuer-rotate-root]',
|
||||||
row: '[data-test-component="info-table-row"]',
|
row: '[data-test-component="info-table-row"]',
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
<div id="qunit-fixture">
|
<div id="qunit-fixture">
|
||||||
<div id="ember-testing-container">
|
<div id="ember-testing-container">
|
||||||
<div id="ember-testing"></div>
|
<div id="ember-testing"></div>
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
|
|
||||||
test('it renders empty state with no data', async function (assert) {
|
test('it renders empty state with no data', async function (assert) {
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Attribution @chartLegend={{this.chartLegend}} />
|
<Clients::Attribution @chartLegend={{this.chartLegend}} />
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@@ -59,7 +58,6 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
|
|
||||||
test('it renders with data for namespaces', async function (assert) {
|
test('it renders with data for namespaces', async function (assert) {
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Attribution
|
<Clients::Attribution
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@totalClientAttribution={{this.totalClientAttribution}}
|
@totalClientAttribution={{this.totalClientAttribution}}
|
||||||
@@ -93,7 +91,6 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
this.start = formatRFC3339(subMonths(this.mockNow, 1));
|
this.start = formatRFC3339(subMonths(this.mockNow, 1));
|
||||||
this.end = formatRFC3339(subMonths(endOfMonth(this.mockNow), 1));
|
this.end = formatRFC3339(subMonths(endOfMonth(this.mockNow), 1));
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Attribution
|
<Clients::Attribution
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@totalClientAttribution={{this.totalClientAttribution}}
|
@totalClientAttribution={{this.totalClientAttribution}}
|
||||||
@@ -147,7 +144,6 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
|
|
||||||
test('it renders single chart for current month', async function (assert) {
|
test('it renders single chart for current month', async function (assert) {
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Attribution
|
<Clients::Attribution
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@totalClientAttribution={{this.totalClientAttribution}}
|
@totalClientAttribution={{this.totalClientAttribution}}
|
||||||
@@ -169,7 +165,6 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
|
|
||||||
test('it renders single chart and correct text for for date range', async function (assert) {
|
test('it renders single chart and correct text for for date range', async function (assert) {
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Attribution
|
<Clients::Attribution
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@totalClientAttribution={{this.totalClientAttribution}}
|
@totalClientAttribution={{this.totalClientAttribution}}
|
||||||
@@ -193,7 +188,6 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
test('it renders with data for selected namespace auth methods for a date range', async function (assert) {
|
test('it renders with data for selected namespace auth methods for a date range', async function (assert) {
|
||||||
this.set('selectedNamespace', 'second');
|
this.set('selectedNamespace', 'second');
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Attribution
|
<Clients::Attribution
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@totalClientAttribution={{this.namespaceMountsData}}
|
@totalClientAttribution={{this.namespaceMountsData}}
|
||||||
@@ -225,7 +219,6 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
|
|
||||||
test('it renders modal', async function (assert) {
|
test('it renders modal', async function (assert) {
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Attribution
|
<Clients::Attribution
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@totalClientAttribution={{this.namespaceMountsData}}
|
@totalClientAttribution={{this.namespaceMountsData}}
|
||||||
@@ -235,7 +228,9 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
/>
|
/>
|
||||||
`);
|
`);
|
||||||
await click('[data-test-attribution-export-button]');
|
await click('[data-test-attribution-export-button]');
|
||||||
assert.dom('.modal.is-active .title').hasText('Export attribution data', 'modal appears to export csv');
|
assert
|
||||||
assert.dom('.modal.is-active').includesText('June 2022 - December 2022');
|
.dom('[data-test-export-modal-title]')
|
||||||
|
.hasText('Export attribution data', 'modal appears to export csv');
|
||||||
|
assert.dom('[ data-test-export-date-range]').includesText('June 2022 - December 2022');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ module('Integration | Component | client count config', function (hooks) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('it should function in edit mode when reporting is disabled', async function (assert) {
|
test('it should function in edit mode when reporting is disabled', async function (assert) {
|
||||||
assert.expect(13);
|
assert.expect(12);
|
||||||
|
|
||||||
this.server.put('/sys/internal/counters/config', (schema, req) => {
|
this.server.put('/sys/internal/counters/config', (schema, req) => {
|
||||||
const { enabled, retention_months } = JSON.parse(req.requestBody);
|
const { enabled, retention_months } = JSON.parse(req.requestBody);
|
||||||
@@ -64,7 +64,6 @@ module('Integration | Component | client count config', function (hooks) {
|
|||||||
this.createModel('disable');
|
this.createModel('disable');
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Config @model={{this.model}} @mode="edit" />
|
<Clients::Config @model={{this.model}} @mode="edit" />
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@@ -86,9 +85,8 @@ module('Integration | Component | client count config', function (hooks) {
|
|||||||
|
|
||||||
await fillIn('[data-test-input="retentionMonths"]', 24);
|
await fillIn('[data-test-input="retentionMonths"]', 24);
|
||||||
await click('[data-test-clients-config-save]');
|
await click('[data-test-clients-config-save]');
|
||||||
assert.dom('.modal.is-active').exists('Modal renders');
|
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-modal-title] span')
|
.dom('[data-test-clients-config-modal="title"]')
|
||||||
.hasText('Turn usage tracking on?', 'Correct modal title renders');
|
.hasText('Turn usage tracking on?', 'Correct modal title renders');
|
||||||
assert.dom('[data-test-clients-config-modal="on"]').exists('Correct modal description block renders');
|
assert.dom('[data-test-clients-config-modal="on"]').exists('Correct modal description block renders');
|
||||||
|
|
||||||
@@ -100,14 +98,14 @@ module('Integration | Component | client count config', function (hooks) {
|
|||||||
|
|
||||||
await click('[data-test-input="enabled"]');
|
await click('[data-test-input="enabled"]');
|
||||||
await click('[data-test-clients-config-save]');
|
await click('[data-test-clients-config-save]');
|
||||||
assert.dom('.modal.is-active').exists('Modal renders');
|
assert.dom('[data-test-clients-config-modal]').exists('Modal renders');
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-modal-title] span')
|
.dom('[data-test-clients-config-modal="title"]')
|
||||||
.hasText('Turn usage tracking off?', 'Correct modal title renders');
|
.hasText('Turn usage tracking off?', 'Correct modal title renders');
|
||||||
assert.dom('[data-test-clients-config-modal="off"]').exists('Correct modal description block renders');
|
assert.dom('[data-test-clients-config-modal="off"]').exists('Correct modal description block renders');
|
||||||
|
|
||||||
await click('[data-test-clients-config-modal="cancel"]');
|
await click('[data-test-clients-config-modal="cancel"]');
|
||||||
assert.dom('.modal.is-active').doesNotExist('Modal is hidden on cancel');
|
assert.dom('[data-test-clients-config-modal]').doesNotExist('Modal is hidden on cancel');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it should function in edit mode when reporting is enabled', async function (assert) {
|
test('it should function in edit mode when reporting is enabled', async function (assert) {
|
||||||
@@ -123,7 +121,6 @@ module('Integration | Component | client count config', function (hooks) {
|
|||||||
this.createModel('enable', true, 24);
|
this.createModel('enable', true, 24);
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Config @model={{this.model}} @mode="edit" />
|
<Clients::Config @model={{this.model}} @mode="edit" />
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@@ -162,7 +159,6 @@ module('Integration | Component | client count config', function (hooks) {
|
|||||||
this.createModel();
|
this.createModel();
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::Config @model={{this.model}} @mode="edit" />
|
<Clients::Config @model={{this.model}} @mode="edit" />
|
||||||
`);
|
`);
|
||||||
await fillIn('[data-test-input="retentionMonths"]', 24);
|
await fillIn('[data-test-input="retentionMonths"]', 24);
|
||||||
|
|||||||
@@ -1433,7 +1433,6 @@ module('Integration | Component | clients/monthly-usage', function (hooks) {
|
|||||||
|
|
||||||
test('it renders empty state with no data', async function (assert) {
|
test('it renders empty state with no data', async function (assert) {
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::MonthlyUsage @chartLegend={{this.chartLegend}} @responseTimestamp={{this.timestamp}}/>
|
<Clients::MonthlyUsage @chartLegend={{this.chartLegend}} @responseTimestamp={{this.timestamp}}/>
|
||||||
`);
|
`);
|
||||||
assert.dom('[data-test-monthly-usage]').exists('monthly usage component renders');
|
assert.dom('[data-test-monthly-usage]').exists('monthly usage component renders');
|
||||||
@@ -1455,7 +1454,6 @@ module('Integration | Component | clients/monthly-usage', function (hooks) {
|
|||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::MonthlyUsage
|
<Clients::MonthlyUsage
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@verticalBarChartData={{this.byMonthActivityData}}
|
@verticalBarChartData={{this.byMonthActivityData}}
|
||||||
|
|||||||
@@ -1444,7 +1444,6 @@ module('Integration | Component | clients/running-total', function (hooks) {
|
|||||||
const expectedNewNonEntity = formatNumber([calculateAverage(NEW_ACTIVITY, 'non_entity_clients')]);
|
const expectedNewNonEntity = formatNumber([calculateAverage(NEW_ACTIVITY, 'non_entity_clients')]);
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::RunningTotal
|
<Clients::RunningTotal
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@selectedAuthMethod={{this.selectedAuthMethod}}
|
@selectedAuthMethod={{this.selectedAuthMethod}}
|
||||||
@@ -1515,7 +1514,6 @@ module('Integration | Component | clients/running-total', function (hooks) {
|
|||||||
const expectedTotalNonEntity = formatNumber([TOTAL_USAGE_COUNTS.non_entity_clients]);
|
const expectedTotalNonEntity = formatNumber([TOTAL_USAGE_COUNTS.non_entity_clients]);
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::RunningTotal
|
<Clients::RunningTotal
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@selectedAuthMethod={{this.selectedAuthMethod}}
|
@selectedAuthMethod={{this.selectedAuthMethod}}
|
||||||
@@ -1558,7 +1556,6 @@ module('Integration | Component | clients/running-total', function (hooks) {
|
|||||||
const expectedNewNonEntity = formatNumber([singleMonthNew.non_entity_clients]);
|
const expectedNewNonEntity = formatNumber([singleMonthNew.non_entity_clients]);
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Clients::RunningTotal
|
<Clients::RunningTotal
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@selectedAuthMethod={{this.selectedAuthMethod}}
|
@selectedAuthMethod={{this.selectedAuthMethod}}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ module('Integration | Component | confirmation-modal', function (hooks) {
|
|||||||
this.set('onConfirm', confirmAction);
|
this.set('onConfirm', confirmAction);
|
||||||
this.set('onClose', closeAction);
|
this.set('onClose', closeAction);
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
@title="Confirmation Modal"
|
@title="Confirmation Modal"
|
||||||
@isActive={{true}}
|
@isActive={{true}}
|
||||||
@@ -30,11 +29,11 @@ module('Integration | Component | confirmation-modal', function (hooks) {
|
|||||||
`);
|
`);
|
||||||
|
|
||||||
assert.dom('[data-test-confirm-button]').isDisabled();
|
assert.dom('[data-test-confirm-button]').isDisabled();
|
||||||
assert.dom('[data-test-modal-div]').hasAttribute('class', 'modal is-highlight is-active');
|
assert.dom('.hds-modal#confirmation-modal').exists('modal is active');
|
||||||
assert.dom('[data-test-confirm-button]').hasText('Plz Continue', 'Confirm button has specified value');
|
assert.dom('[data-test-confirm-button]').hasText('Plz Continue', 'Confirm button has specified value');
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-modal-title]')
|
.dom('[data-test-confirmation-modal-title] [data-test-icon="alert-triangle"]')
|
||||||
.hasStyle({ color: 'rgb(160, 125, 2)' }, 'title exists with warning header');
|
.exists('title has with warning icon');
|
||||||
await fillIn('[data-test-confirmation-modal-input="Confirmation Modal"]', 'Destructive Thing');
|
await fillIn('[data-test-confirmation-modal-input="Confirmation Modal"]', 'Destructive Thing');
|
||||||
assert.dom('[data-test-confirm-button="Confirmation Modal"]').isNotDisabled();
|
assert.dom('[data-test-confirm-button="Confirmation Modal"]').isNotDisabled();
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,12 @@ import { ARRAY_OF_MONTHS } from 'core/utils/date-formatters';
|
|||||||
import timestamp from 'core/utils/timestamp';
|
import timestamp from 'core/utils/timestamp';
|
||||||
|
|
||||||
const SELECTORS = {
|
const SELECTORS = {
|
||||||
monthDropdown: '[data-test-popup-menu-trigger="month"]',
|
monthDropdown: '[data-test-toggle-month]',
|
||||||
specificMonth: (m) => `[data-test-dropdown-month="${m}"]`,
|
specificMonth: (m) => `[data-test-dropdown-month="${m}"]`,
|
||||||
yearDropdown: '[data-test-popup-menu-trigger="year"]',
|
yearDropdown: '[data-test-toggle-year]',
|
||||||
specificYear: (y) => `[data-test-dropdown-year="${y}"]`,
|
specificYear: (y) => `[data-test-dropdown-year="${y}"]`,
|
||||||
|
|
||||||
submitButton: '[data-test-date-dropdown-submit]',
|
submitButton: '[data-test-date-dropdown-submit]',
|
||||||
cancelButton: '[data-test-date-dropdown-cancel]',
|
monthOptions: '[data-test-dropdown-month]',
|
||||||
monthOptions: '[data-test-month-list] button',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module('Integration | Component | date-dropdown', function (hooks) {
|
module('Integration | Component | date-dropdown', function (hooks) {
|
||||||
@@ -34,27 +32,11 @@ module('Integration | Component | date-dropdown', function (hooks) {
|
|||||||
|
|
||||||
test('it renders dropdown', async function (assert) {
|
test('it renders dropdown', async function (assert) {
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div class="is-flex-align-baseline">
|
<div class="has-padding-l">
|
||||||
<DateDropdown/>
|
<DateDropdown/>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
assert.dom(SELECTORS.submitButton).hasText('Submit', 'button renders default text');
|
assert.dom(SELECTORS.submitButton).hasText('Submit', 'button renders default text');
|
||||||
assert.dom(SELECTORS.cancelButton).doesNotExist('it does not render cancel button by default');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it fires off cancel callback', async function (assert) {
|
|
||||||
assert.expect(2);
|
|
||||||
const onCancel = () => {
|
|
||||||
assert.ok('fires onCancel callback');
|
|
||||||
};
|
|
||||||
this.set('onCancel', onCancel);
|
|
||||||
await render(hbs`
|
|
||||||
<div class="is-flex-align-baseline">
|
|
||||||
<DateDropdown @handleCancel={{this.onCancel}} @submitText="Save"/>
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
assert.dom(SELECTORS.submitButton).hasText('Save', 'button renders passed in text');
|
|
||||||
await click(SELECTORS.cancelButton);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it renders dropdown and selects month and year', async function (assert) {
|
test('it renders dropdown and selects month and year', async function (assert) {
|
||||||
@@ -74,7 +56,7 @@ module('Integration | Component | date-dropdown', function (hooks) {
|
|||||||
this.set('parentAction', parentAction);
|
this.set('parentAction', parentAction);
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div class="is-flex-align-baseline">
|
<div class="has-padding-l">
|
||||||
<DateDropdown
|
<DateDropdown
|
||||||
@handleSubmit={{this.parentAction}}
|
@handleSubmit={{this.parentAction}}
|
||||||
@dateType="start"
|
@dateType="start"
|
||||||
@@ -112,7 +94,7 @@ module('Integration | Component | date-dropdown', function (hooks) {
|
|||||||
test('selecting month first: current year enabled when current month selected', async function (assert) {
|
test('selecting month first: current year enabled when current month selected', async function (assert) {
|
||||||
assert.expect(5);
|
assert.expect(5);
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div class="is-flex-align-baseline">
|
<div class="has-padding-l">
|
||||||
<DateDropdown/>
|
<DateDropdown/>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
@@ -129,7 +111,7 @@ module('Integration | Component | date-dropdown', function (hooks) {
|
|||||||
test('selecting month first: it disables current year when future months selected', async function (assert) {
|
test('selecting month first: it disables current year when future months selected', async function (assert) {
|
||||||
assert.expect(5);
|
assert.expect(5);
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div class="is-flex-align-baseline">
|
<div class="has-padding-l">
|
||||||
<DateDropdown/>
|
<DateDropdown/>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
@@ -149,7 +131,7 @@ module('Integration | Component | date-dropdown', function (hooks) {
|
|||||||
test('selecting year first: it disables future months when current year selected', async function (assert) {
|
test('selecting year first: it disables future months when current year selected', async function (assert) {
|
||||||
assert.expect(12);
|
assert.expect(12);
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div class="is-flex-align-baseline">
|
<div class="has-padding-l">
|
||||||
<DateDropdown/>
|
<DateDropdown/>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
@@ -170,7 +152,7 @@ module('Integration | Component | date-dropdown', function (hooks) {
|
|||||||
test('selecting year first: it enables all months when past year is selected', async function (assert) {
|
test('selecting year first: it enables all months when past year is selected', async function (assert) {
|
||||||
assert.expect(12);
|
assert.expect(12);
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<div class="is-flex-align-baseline">
|
<div class="has-padding-l">
|
||||||
<DateDropdown/>
|
<DateDropdown/>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupRenderingTest } from 'ember-qunit';
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
import { click, render, resetOnerror, setupOnerror } from '@ember/test-helpers';
|
import { click, render, resetOnerror, setupOnerror } from '@ember/test-helpers';
|
||||||
import { isPresent } from 'ember-cli-page-object';
|
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
|
|
||||||
@@ -28,25 +27,23 @@ module('Integration | Component | download button', function (hooks) {
|
|||||||
|
|
||||||
test('it renders', async function (assert) {
|
test('it renders', async function (assert) {
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<DownloadButton class="button">
|
<DownloadButton /> `);
|
||||||
<Icon @name="download" />
|
assert.dom(SELECTORS.icon).exists('renders download icon');
|
||||||
Download
|
assert.dom(SELECTORS.button).hasText('Download', 'renders default text');
|
||||||
</DownloadButton>
|
});
|
||||||
`);
|
|
||||||
assert.dom(SELECTORS.button).hasClass('button');
|
test('it renders passed args', async function (assert) {
|
||||||
assert.ok(isPresent(SELECTORS.icon), 'renders yielded icon');
|
await render(hbs`
|
||||||
assert.dom(SELECTORS.button).hasTextContaining('Download', 'renders yielded text');
|
<DownloadButton @text="I do something" @hideIcon={{true}} /> `);
|
||||||
|
assert.dom(SELECTORS.icon).doesNotExist('hides icon');
|
||||||
|
assert.dom(SELECTORS.button).hasText('I do something', 'renders passed text');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it downloads with defaults when only passed @data arg', async function (assert) {
|
test('it downloads with defaults when only passed @data arg', async function (assert) {
|
||||||
assert.expect(3);
|
assert.expect(3);
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<DownloadButton class="button"
|
<DownloadButton @data={{this.data}} />
|
||||||
@data={{this.data}}
|
|
||||||
>
|
|
||||||
Download
|
|
||||||
</DownloadButton>
|
|
||||||
`);
|
`);
|
||||||
await click(SELECTORS.button);
|
await click(SELECTORS.button);
|
||||||
const [filename, content, extension] = this.downloadSpy.getCall(0).args;
|
const [filename, content, extension] = this.downloadSpy.getCall(0).args;
|
||||||
@@ -59,16 +56,13 @@ module('Integration | Component | download button', function (hooks) {
|
|||||||
assert.expect(3);
|
assert.expect(3);
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<DownloadButton class="button"
|
<DownloadButton
|
||||||
@data={{this.data}}
|
@data={{this.data}}
|
||||||
@filename={{this.filename}}
|
@filename={{this.filename}}
|
||||||
@mime={{this.mime}}
|
@mime={{this.mime}}
|
||||||
@extension={{this.extension}}
|
@extension={{this.extension}}
|
||||||
>
|
/>
|
||||||
Download
|
|
||||||
</DownloadButton>
|
|
||||||
`);
|
`);
|
||||||
|
|
||||||
await click(SELECTORS.button);
|
await click(SELECTORS.button);
|
||||||
const [filename, content, extension] = this.downloadSpy.getCall(0).args;
|
const [filename, content, extension] = this.downloadSpy.getCall(0).args;
|
||||||
assert.ok(filename.includes(`${this.filename}-`), 'filename added to ISO string');
|
assert.ok(filename.includes(`${this.filename}-`), 'filename added to ISO string');
|
||||||
@@ -80,9 +74,7 @@ module('Integration | Component | download button', function (hooks) {
|
|||||||
assert.expect(3);
|
assert.expect(3);
|
||||||
this.fetchData = () => 'this is fetched data from a parent function';
|
this.fetchData = () => 'this is fetched data from a parent function';
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<DownloadButton class="button" @fetchData={{this.fetchData}} >
|
<DownloadButton @fetchData={{this.fetchData}} />
|
||||||
Download
|
|
||||||
</DownloadButton>
|
|
||||||
`);
|
`);
|
||||||
|
|
||||||
await click(SELECTORS.button);
|
await click(SELECTORS.button);
|
||||||
@@ -103,7 +95,7 @@ module('Integration | Component | download button', function (hooks) {
|
|||||||
});
|
});
|
||||||
this.fetchData = () => 'this is fetched data from a parent function';
|
this.fetchData = () => 'this is fetched data from a parent function';
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<DownloadButton class="button" @data={{this.data}} @fetchData={{this.fetchData}} />
|
<DownloadButton @data={{this.data}} @fetchData={{this.fetchData}} />
|
||||||
`);
|
`);
|
||||||
resetOnerror();
|
resetOnerror();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -45,9 +45,7 @@ module('Integration | Component | keymgmt/key-edit', function (hooks) {
|
|||||||
// TODO: Add capabilities tests
|
// TODO: Add capabilities tests
|
||||||
test('it renders show view as default', async function (assert) {
|
test('it renders show view as default', async function (assert) {
|
||||||
assert.expect(8);
|
assert.expect(8);
|
||||||
await render(
|
await render(hbs`<Keymgmt::KeyEdit @model={{this.model}} @tab={{this.tab}} />`);
|
||||||
hbs`<Keymgmt::KeyEdit @model={{this.model}} @tab={{this.tab}} /><div id="modal-wormhole" />`
|
|
||||||
);
|
|
||||||
assert.dom('[data-test-secret-header]').hasText('Unicorns', 'Shows key name');
|
assert.dom('[data-test-secret-header]').hasText('Unicorns', 'Shows key name');
|
||||||
assert.dom('[data-test-keymgmt-key-toolbar]').exists('Subnav toolbar exists');
|
assert.dom('[data-test-keymgmt-key-toolbar]').exists('Subnav toolbar exists');
|
||||||
assert.dom('[data-test-tab="Details"]').exists('Details tab exists');
|
assert.dom('[data-test-tab="Details"]').exists('Details tab exists');
|
||||||
@@ -71,9 +69,7 @@ module('Integration | Component | keymgmt/key-edit', function (hooks) {
|
|||||||
this.set('mode', 'edit');
|
this.set('mode', 'edit');
|
||||||
this.set('model', model);
|
this.set('model', model);
|
||||||
|
|
||||||
await render(
|
await render(hbs`<Keymgmt::KeyEdit @model={{this.model}} @mode={{this.mode}} />`);
|
||||||
hbs`<Keymgmt::KeyEdit @model={{this.model}} @mode={{this.mode}} /><div id="modal-wormhole" />`
|
|
||||||
);
|
|
||||||
assert.dom('[data-test-secret-header]').hasText('Edit Key', 'Shows edit header');
|
assert.dom('[data-test-secret-header]').hasText('Edit Key', 'Shows edit header');
|
||||||
assert.dom('[data-test-keymgmt-key-toolbar]').doesNotExist('Subnav toolbar does not exist');
|
assert.dom('[data-test-keymgmt-key-toolbar]').doesNotExist('Subnav toolbar does not exist');
|
||||||
assert.dom('[data-test-tab="Details"]').doesNotExist('Details tab does not exist');
|
assert.dom('[data-test-tab="Details"]').doesNotExist('Details tab does not exist');
|
||||||
@@ -86,9 +82,7 @@ module('Integration | Component | keymgmt/key-edit', function (hooks) {
|
|||||||
this.set('mode', 'create');
|
this.set('mode', 'create');
|
||||||
this.set('model', model);
|
this.set('model', model);
|
||||||
|
|
||||||
await render(
|
await render(hbs`<Keymgmt::KeyEdit @model={{this.model}} @mode={{this.mode}} />`);
|
||||||
hbs`<Keymgmt::KeyEdit @model={{this.model}} @mode={{this.mode}} /><div id="modal-wormhole" />`
|
|
||||||
);
|
|
||||||
assert.dom('[data-test-secret-header]').hasText('Create Key', 'Shows edit header');
|
assert.dom('[data-test-secret-header]').hasText('Create Key', 'Shows edit header');
|
||||||
assert.dom('[data-test-keymgmt-key-toolbar]').doesNotExist('Subnav toolbar does not exist');
|
assert.dom('[data-test-keymgmt-key-toolbar]').doesNotExist('Subnav toolbar does not exist');
|
||||||
assert.dom('[data-test-tab="Details"]').doesNotExist('Details tab does not exist');
|
assert.dom('[data-test-tab="Details"]').doesNotExist('Details tab does not exist');
|
||||||
@@ -100,9 +94,7 @@ module('Integration | Component | keymgmt/key-edit', function (hooks) {
|
|||||||
const store = this.owner.lookup('service:store');
|
const store = this.owner.lookup('service:store');
|
||||||
this.model = store.createRecord('keymgmt/key');
|
this.model = store.createRecord('keymgmt/key');
|
||||||
this.set('mode', 'create');
|
this.set('mode', 'create');
|
||||||
await render(
|
await render(hbs`<Keymgmt::KeyEdit @model={{this.model}} @mode={{this.mode}} />`);
|
||||||
hbs`<Keymgmt::KeyEdit @model={{this.model}} @mode={{this.mode}} /><div id="modal-wormhole" />`
|
|
||||||
);
|
|
||||||
assert.dom('[data-test-input="type"]').hasValue('rsa-2048', 'Has type rsa-2048 by default');
|
assert.dom('[data-test-input="type"]').hasValue('rsa-2048', 'Has type rsa-2048 by default');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -199,14 +199,13 @@ module('Integration | Component | kubernetes | Page::Configure', function (hooks
|
|||||||
|
|
||||||
await render(
|
await render(
|
||||||
hbs`
|
hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<Page::Configure @model={{this.editModel}} @breadcrumbs={{this.breadcrumbs}} />
|
<Page::Configure @model={{this.editModel}} @breadcrumbs={{this.breadcrumbs}} />
|
||||||
`,
|
`,
|
||||||
{ owner: this.engine }
|
{ owner: this.engine }
|
||||||
);
|
);
|
||||||
await click('[data-test-config-save]');
|
await click('[data-test-config-save]');
|
||||||
assert
|
assert
|
||||||
.dom('.modal-card-body')
|
.dom('[data-test-edit-config-body]')
|
||||||
.hasText(
|
.hasText(
|
||||||
'Making changes to your configuration may affect how Vault will reach the Kubernetes API and authenticate with it. Are you sure?',
|
'Making changes to your configuration may affect how Vault will reach the Kubernetes API and authenticate with it. Are you sure?',
|
||||||
'Confirm modal renders'
|
'Confirm modal renders'
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ module('Integration | Component | ldap | AccountsCheckedOut', function (hooks) {
|
|||||||
this.renderComponent = () => {
|
this.renderComponent = () => {
|
||||||
return render(
|
return render(
|
||||||
hbs`
|
hbs`
|
||||||
<div id="modal-wormhole"></div>
|
|
||||||
<AccountsCheckedOut
|
<AccountsCheckedOut
|
||||||
@libraries={{array this.library}}
|
@libraries={{array this.library}}
|
||||||
@statuses={{this.statuses}}
|
@statuses={{this.statuses}}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user