mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 11:38:02 +00:00
UI/add select dropdown (#7102)
* add SelectDropdown * use SelectDropdown instead of HttpRequestsDropdown * use html selector instead of class name * ensure SelectDropdown still works when rendered inside a Toolbar * add tests * remove old HttpRequests component * make SelectDropdown example easier to read in Storybook * add isFullwidth prop * add SelectDropbown inside a Toolbar story * fix tests * remove actions block and call this.onChange directly * replace dropdownLabel with label * rename SelectDropdown to SelecT * add test for onChange * remove selectedItem prop since we don't need it * make Select accept options as an array of strings or objects * Revert "remove selectedItem prop since we don't need it" This reverts commit 7278516de87bb1df60482edb005137252819931e. * use Select inside TtlPicker * remove debugger * use a test selector * fix pki test selectors * improve storybook docs * fix selected value in ttl picker * ensure httprequests dropdown updates the selected item * ensure select dropdown correctly matches selectedItem * rename selectedItem to selectedValue * remove debugger lol * update selectedItem test * add valueAttribute and labelAttribute to Storybook knobs * udpate jsdocs * remove old httprequestsdropdown component * add note that onChange will receive value of select * use Select inside AuthForm * use correct test selector
This commit is contained in:
@@ -25,6 +25,21 @@ export default Component.extend({
|
|||||||
classNames: ['http-requests-container'],
|
classNames: ['http-requests-container'],
|
||||||
counters: null,
|
counters: null,
|
||||||
timeWindow: 'All',
|
timeWindow: 'All',
|
||||||
|
dropdownOptions: computed('counters', function() {
|
||||||
|
let counters = this.counters || [];
|
||||||
|
let options = ['All', 'Last 12 Months'];
|
||||||
|
if (counters.length) {
|
||||||
|
const years = counters
|
||||||
|
.map(counter => {
|
||||||
|
const year = new Date(counter.start_time);
|
||||||
|
return year.getUTCFullYear().toString();
|
||||||
|
})
|
||||||
|
.uniq();
|
||||||
|
years.sort().reverse();
|
||||||
|
options = options.concat(years);
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}),
|
||||||
filteredCounters: computed('counters', 'timeWindow', function() {
|
filteredCounters: computed('counters', 'timeWindow', function() {
|
||||||
const { counters, timeWindow } = this;
|
const { counters, timeWindow } = this;
|
||||||
if (timeWindow === 'All') {
|
if (timeWindow === 'All') {
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
import Component from '@ember/component';
|
|
||||||
import { computed } from '@ember/object';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module HttpRequestsDropdown
|
|
||||||
* HttpRequestsDropdown components are used to render a dropdown that filters the HttpRequestsBarChart.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```js
|
|
||||||
* <HttpRequestsDropdown @counters={counters} />
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param counters=null {Array} - A list of objects containing the total number of HTTP Requests for each month. `counters` should be the response from the `/internal/counters/requests` endpoint which looks like:
|
|
||||||
* COUNTERS = [
|
|
||||||
* {
|
|
||||||
* "start_time": "2019-05-01T00:00:00Z",
|
|
||||||
* "total": 50
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default Component.extend({
|
|
||||||
classNames: ['http-requests-dropdown'],
|
|
||||||
counters: null,
|
|
||||||
timeWindow: 'All',
|
|
||||||
options: computed('counters', function() {
|
|
||||||
let counters = this.counters || [];
|
|
||||||
let options = [];
|
|
||||||
if (counters.length) {
|
|
||||||
const years = counters
|
|
||||||
.map(counter => {
|
|
||||||
const year = new Date(counter.start_time);
|
|
||||||
return year.getUTCFullYear().toString();
|
|
||||||
})
|
|
||||||
.uniq();
|
|
||||||
years.sort().reverse();
|
|
||||||
options = options.concat(years);
|
|
||||||
}
|
|
||||||
return options;
|
|
||||||
}),
|
|
||||||
onChange() {},
|
|
||||||
actions: {
|
|
||||||
onSelectTimeWindow(e) {
|
|
||||||
const newValue = e.target.value;
|
|
||||||
const { timeWindow } = this;
|
|
||||||
if (newValue !== timeWindow) {
|
|
||||||
this.onChange(newValue);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
34
ui/app/components/select.js
Normal file
34
ui/app/components/select.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @module Select
|
||||||
|
* Select components are used to render a dropdown.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js
|
||||||
|
* <Select @label='Date Range' @options={{[{ value: 'berry', label: 'Berry' }]}} @onChange={{onChange}}/>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param label=null {String} - The label for the select element.
|
||||||
|
* @param options=null {Array} - A list of items that the user will select from. This can be an array of strings or objects.
|
||||||
|
* @param [selectedValue=null] {String} - The currently selected item. Can also be used to set the default selected item. This should correspond to the `value` of one of the `<option>`s.
|
||||||
|
* @param [name=null] {String} - The name of the select, used for the test selector.
|
||||||
|
* @param [valueAttribute=value] {String} - When `options` is an array objects, the key to check for when assigning the option elements value.
|
||||||
|
* @param [labelAttribute=label] {String} - When `options` is an array objects, the key to check for when assigning the option elements' inner text.
|
||||||
|
* @param [isInline=false] {Bool} - Whether or not the select should be displayed as inline-block or block.
|
||||||
|
* @param [isFullwidth=false] {Bool} - Whether or not the select should take up the full width of the parent element.
|
||||||
|
* @param onChange=null {Func} - The action to take once the user has selected an item. This method will be passed the `value` of the select.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNames: ['field'],
|
||||||
|
label: null,
|
||||||
|
selectedValue: null,
|
||||||
|
name: null,
|
||||||
|
options: null,
|
||||||
|
valueAttribute: 'value',
|
||||||
|
labelAttribute: 'label',
|
||||||
|
isInline: false,
|
||||||
|
isFullwidth: false,
|
||||||
|
onChange() {},
|
||||||
|
});
|
||||||
@@ -24,6 +24,11 @@
|
|||||||
.select {
|
.select {
|
||||||
min-width: 190px;
|
min-width: 190px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
padding: $spacing-xs;
|
||||||
|
color: $grey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-scroller {
|
.toolbar-scroller {
|
||||||
@@ -95,11 +100,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-label {
|
|
||||||
padding: $spacing-xs;
|
|
||||||
color: $grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-separator {
|
.toolbar-separator {
|
||||||
border-right: $light-border;
|
border-right: $light-border;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|||||||
@@ -32,27 +32,15 @@
|
|||||||
data-test-auth-error
|
data-test-auth-error
|
||||||
/>
|
/>
|
||||||
{{#if (or (not hasMethodsWithPath) (not selectedAuthIsPath))}}
|
{{#if (or (not hasMethodsWithPath) (not selectedAuthIsPath))}}
|
||||||
<div class="field">
|
<Select
|
||||||
<label for="selectedMethod" class="is-label">
|
@label='Method'
|
||||||
Method
|
@name='auth-method'
|
||||||
</label>
|
@options={{supported-auth-backends}}
|
||||||
<div class="control is-expanded" >
|
@valueAttribute={{'type'}}
|
||||||
<div class="select is-fullwidth">
|
@labelAttribute={{'typeDisplay'}}
|
||||||
<select
|
@isFullwidth={{true}}
|
||||||
name="selectedMethod"
|
@onChange={{action (mut selectedAuth)}}
|
||||||
id="selectedMethod"
|
/>
|
||||||
onchange={{action (mut selectedAuth) value="target.value"}}
|
|
||||||
data-test-method-select
|
|
||||||
>
|
|
||||||
{{#each (supported-auth-backends) as |method|}}
|
|
||||||
<option selected={{eq selectedAuthBackend.type method.type}} value={{method.type}}>
|
|
||||||
{{method.typeDisplay}}
|
|
||||||
</option>
|
|
||||||
{{/each}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if (or (eq this.selectedAuthBackend.type "jwt") (eq this.selectedAuthBackend.type "oidc"))}}
|
{{#if (or (eq this.selectedAuthBackend.type "jwt") (eq this.selectedAuthBackend.type "oidc"))}}
|
||||||
<AuthJwt
|
<AuthJwt
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
{{#if (gt counters.length 1) }}
|
{{#if (gt counters.length 1) }}
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<HttpRequestsDropdown @counters={{counters}} @onChange={{action "updateTimeWindow"}} @timeWindow={{timeWindow}}/>
|
<Select
|
||||||
|
@label='Date Range'
|
||||||
|
@name='requests-timewindow'
|
||||||
|
@options={{dropdownOptions}}
|
||||||
|
@onChange={{action "updateTimeWindow"}}
|
||||||
|
@selectedValue={{timeWindow}}
|
||||||
|
@isInline={{true}}
|
||||||
|
/>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
|
||||||
<HttpRequestsBarChart @counters={{filteredCounters}} />
|
<HttpRequestsBarChart @counters={{filteredCounters}} />
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
<label for="date-range" class="is-label toolbar-label">
|
|
||||||
Date Range
|
|
||||||
</label>
|
|
||||||
<div class="select">
|
|
||||||
<select class="select" id="date-range" data-test-date-range name="selectedTimeWindow" data-test-timewindow-select onchange={{action "onSelectTimeWindow"}}>
|
|
||||||
<option value="All" selected={{eq timeWindow "All"}}>All</option>/>
|
|
||||||
<option value="Last 12 Months" selected={{eq timeWindow "Last 12 Months"}}>Last 12 Months</option>
|
|
||||||
{{#each options as |op|}}
|
|
||||||
<option value={{op}} selected={{eq timeWindow op}}>{{op}}</option>
|
|
||||||
{{/each}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
29
ui/app/templates/components/select.hbs
Normal file
29
ui/app/templates/components/select.hbs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
{{#if label}}
|
||||||
|
<label
|
||||||
|
for="select-{{this.elementId}}"
|
||||||
|
class="is-label"
|
||||||
|
data-test-select-label
|
||||||
|
>
|
||||||
|
{{label}}
|
||||||
|
</label>
|
||||||
|
{{/if}}
|
||||||
|
<div class="control {{if isInline "select is-inline-block"}}">
|
||||||
|
<div class="select {{if isFullwidth "is-fullwidth"}}">
|
||||||
|
<select
|
||||||
|
class="select"
|
||||||
|
id="select-{{this.elementId}}"
|
||||||
|
onchange={{action this.onChange value="target.value"}}
|
||||||
|
data-test-select={{name}}
|
||||||
|
>
|
||||||
|
{{#each options as |op|}}
|
||||||
|
<option
|
||||||
|
value={{or (get op valueAttribute) op}}
|
||||||
|
selected={{eq selectedValue (or (get op valueAttribute) op)}}>
|
||||||
|
{{or (get op labelAttribute) op}}
|
||||||
|
</option>
|
||||||
|
{{/each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@@ -102,18 +102,17 @@ export default Component.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
changedValue(key, event) {
|
changedValue(key, value) {
|
||||||
let { type, value, checked } = event.target;
|
if (value && key === 'time') {
|
||||||
let val = type === 'checkbox' ? checked : value;
|
value = parseInt(value, 10);
|
||||||
if (val && key === 'time') {
|
if (Number.isNaN(value)) {
|
||||||
val = parseInt(val, 10);
|
|
||||||
if (Number.isNaN(val)) {
|
|
||||||
this.set('errorMessage', ERROR_MESSAGE);
|
this.set('errorMessage', ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.set('errorMessage', null);
|
this.set('errorMessage', null);
|
||||||
set(this, key, val);
|
|
||||||
|
set(this, key, value);
|
||||||
this.onChange(this.TTL);
|
this.onChange(this.TTL);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,18 +2,16 @@
|
|||||||
<MessageError @errorMessage={{errorMessage}} data-test-ttl-error />
|
<MessageError @errorMessage={{errorMessage}} data-test-ttl-error />
|
||||||
<div class="field is-grouped">
|
<div class="field is-grouped">
|
||||||
<div class="control is-expanded">
|
<div class="control is-expanded">
|
||||||
<input data-test-ttl-value value={{time}} id="time-{{elementId}}" type="text" name="time" class="input" oninput={{action 'changedValue' 'time'}}
|
<input data-test-ttl-value value={{time}} id="time-{{elementId}}" type="text" name="time" class="input" oninput={{action (action 'changedValue' 'time') value="target.value"}}
|
||||||
pattern="[0-9]*" />
|
pattern="[0-9]*" />
|
||||||
</div>
|
</div>
|
||||||
<div class="control is-expanded">
|
<div class="control is-expanded">
|
||||||
<div class="select is-fullwidth">
|
<Select
|
||||||
<select data-test-ttl-unit name="unit" id="unit" onchange={{action 'changedValue' 'unit'}}>
|
@name='ttl-unit'
|
||||||
{{#each unitOptions as |unitOption|}}
|
@options={{unitOptions}}
|
||||||
<option selected={{eq unit unitOption.value}} value={{unitOption.value}}>
|
@onChange={{action 'changedValue' 'unit'}}
|
||||||
{{unitOption.label}}
|
@selectedValue={{unit.value}}
|
||||||
</option>
|
@isFullwidth={{true}}
|
||||||
{{/each}}
|
/>
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
<!--THIS FILE IS AUTO GENERATED. This file is generated from JSDoc comments in app/components/http-requests-dropdown.js. To make changes, first edit that file and run "yarn gen-story-md http-requests-dropdown" to re-generate the content.-->
|
|
||||||
|
|
||||||
## HttpRequestsDropdown
|
|
||||||
HttpRequestsDropdown components are used to render a dropdown that filters the HttpRequestsBarChart.
|
|
||||||
|
|
||||||
|
|
||||||
| Param | Type | Default | Description |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| counters | <code>Array</code> | <code></code> | A list of objects containing the total number of HTTP Requests for each month. `counters` should be the response from the `/internal/counters/requests` endpoint. |
|
|
||||||
|
|
||||||
**Example**
|
|
||||||
|
|
||||||
```js
|
|
||||||
<HttpRequestsDropdown @counters={counters} />
|
|
||||||
```
|
|
||||||
|
|
||||||
**See**
|
|
||||||
|
|
||||||
- [Uses of HttpRequestsDropdown](https://github.com/hashicorp/vault/search?l=Handlebars&q=HttpRequestsDropdown+OR+http-requests-dropdown)
|
|
||||||
- [HttpRequestsDropdown Source Code](https://github.com/hashicorp/vault/blob/master/ui/app/components/http-requests-dropdown.js)
|
|
||||||
|
|
||||||
---
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/* eslint-disable import/extensions */
|
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
|
||||||
import { storiesOf } from '@storybook/ember';
|
|
||||||
import { withKnobs, object } from '@storybook/addon-knobs';
|
|
||||||
import notes from './http-requests-dropdown.md';
|
|
||||||
|
|
||||||
const COUNTERS = [
|
|
||||||
{ start_time: '2019-04-01T00:00:00Z', total: 5500 },
|
|
||||||
{ start_time: '2019-05-01T00:00:00Z', total: 4500 },
|
|
||||||
{ start_time: '2019-06-01T00:00:00Z', total: 5000 },
|
|
||||||
];
|
|
||||||
|
|
||||||
storiesOf('HttpRequests/Dropdown/', module)
|
|
||||||
.addParameters({ options: { showPanel: true } })
|
|
||||||
.addDecorator(withKnobs())
|
|
||||||
.add(
|
|
||||||
`HttpRequestsDropdown`,
|
|
||||||
() => ({
|
|
||||||
template: hbs`
|
|
||||||
<h5 class="title is-5">Http Requests Dropdown</h5>
|
|
||||||
<HttpRequestsDropdown @counters={{counters}}/>
|
|
||||||
`,
|
|
||||||
context: {
|
|
||||||
counters: object('counters', COUNTERS),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{ notes }
|
|
||||||
);
|
|
||||||
33
ui/stories/select.md
Normal file
33
ui/stories/select.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<!--THIS FILE IS AUTO GENERATED. This file is generated from JSDoc comments in app/components/select.js. To make changes, first edit that file and run "yarn gen-story-md select" to re-generate the content.-->
|
||||||
|
|
||||||
|
## Select
|
||||||
|
Select components are used to render a dropdown.
|
||||||
|
|
||||||
|
|
||||||
|
| Param | Type | Default | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| label | <code>String</code> | <code></code> | The label for the select element. |
|
||||||
|
| options | <code>Array</code> | <code></code> | A list of items that the user will select from. This can be an array of strings or objects. |
|
||||||
|
| [name] | <code>String</code> | <code></code> | The name of the select, used for the test selector. |
|
||||||
|
| [selectedValue] | <code>String</code> | <code></code> | The currently selected item. Can also be used to set the default selected item. This should correspond to the `value` of one of the `<option>`s. |
|
||||||
|
| [valueAttribute] | <code>String</code> | <code>value</code> | When `options` is an array objects, the key to check for when assigning the option elements value. |
|
||||||
|
| [labelAttribute] | <code>String</code> | <code>label</code> | When `options` is an array objects, the key to check for when assigning the option elements' inner text. |
|
||||||
|
| [isInline] | <code>Bool</code> | <code>false</code> | Whether or not the select should be displayed as inline-block or block. |
|
||||||
|
| [isFullwidth] | <code>Bool</code> | <code>false</code> | Whether or not the select should take up the full width of the parent element. |
|
||||||
|
| onChange | <code>Func</code> | <code></code> | The action to take once the user has selected an item. This method will be passed the `value` of the select. |
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```js
|
||||||
|
<Select
|
||||||
|
@label='Date Range'
|
||||||
|
@options={{[{ value: 'berry', label: 'Berry' }]}}
|
||||||
|
@onChange={{onChange}}/>
|
||||||
|
```
|
||||||
|
|
||||||
|
**See**
|
||||||
|
|
||||||
|
- [Uses of Select](https://github.com/hashicorp/vault/search?l=Handlebars&q=Select+OR+select)
|
||||||
|
- [Select Source Code](https://github.com/hashicorp/vault/blob/master/ui/app/components/select.js)
|
||||||
|
|
||||||
|
---
|
||||||
65
ui/stories/select.stories.js
Normal file
65
ui/stories/select.stories.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/* eslint-disable import/extensions */
|
||||||
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
import { storiesOf } from '@storybook/ember';
|
||||||
|
import { withKnobs, object, text, boolean, select } from '@storybook/addon-knobs';
|
||||||
|
import notes from './select.md';
|
||||||
|
|
||||||
|
const OPTIONS = [
|
||||||
|
{ value: 'mon', label: 'Monday', spanish: 'lunes' },
|
||||||
|
{ value: 'tues', label: 'Tuesday', spanish: 'martes' },
|
||||||
|
{ value: 'weds', label: 'Wednesday', spanish: 'miercoles' },
|
||||||
|
];
|
||||||
|
|
||||||
|
storiesOf('Select/', module)
|
||||||
|
.addParameters({ options: { showPanel: true } })
|
||||||
|
.addDecorator(withKnobs())
|
||||||
|
.add(
|
||||||
|
`Select`,
|
||||||
|
() => ({
|
||||||
|
template: hbs`
|
||||||
|
<h5 class="title is-5">Select</h5>
|
||||||
|
<Select
|
||||||
|
@options={{options}}
|
||||||
|
@label={{label}}
|
||||||
|
@isInline={{isInline}}
|
||||||
|
@isFullwidth={{isFullwidth}}
|
||||||
|
@valueAttribute={{valueAttribute}}
|
||||||
|
@labelAttribute={{labelAttribute}}
|
||||||
|
@selectedValue={{selectedValue}}
|
||||||
|
/>
|
||||||
|
`,
|
||||||
|
context: {
|
||||||
|
options: object('options', OPTIONS),
|
||||||
|
label: text('label', 'Day of the week'),
|
||||||
|
isFullwidth: boolean('isFullwidth', false),
|
||||||
|
isInline: boolean('isInline', false),
|
||||||
|
valueAttribute: select('valueAttribute', Object.keys(OPTIONS[0]), 'value'),
|
||||||
|
labelAttribute: select('labelAttribute', Object.keys(OPTIONS[0]), 'label'),
|
||||||
|
selectedValue: select('selectedValue', OPTIONS.map(o => o.label), 'tues'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{ notes }
|
||||||
|
)
|
||||||
|
.add(
|
||||||
|
`Select in a Toolbar`,
|
||||||
|
() => ({
|
||||||
|
template: hbs`
|
||||||
|
<h5 class="title is-5">Select</h5>
|
||||||
|
<Toolbar>
|
||||||
|
<Select
|
||||||
|
@options={{options}}
|
||||||
|
@label={{label}}
|
||||||
|
@valueAttribute={{valueAttribute}}
|
||||||
|
@labelAttribute={{labelAttribute}}
|
||||||
|
@isInline={{true}}/>
|
||||||
|
</Toolbar>
|
||||||
|
`,
|
||||||
|
context: {
|
||||||
|
label: text('label', 'Day of the week'),
|
||||||
|
options: object('options', OPTIONS),
|
||||||
|
valueAttribute: select('valueAttribute', Object.keys(OPTIONS[0]), 'value'),
|
||||||
|
labelAttribute: select('labelAttribute', Object.keys(OPTIONS[0]), 'label'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{ notes }
|
||||||
|
);
|
||||||
@@ -18,8 +18,8 @@ module('Acceptance | settings/configure/secrets/pki/crl', function(hooks) {
|
|||||||
await page.visit({ backend: path, section: 'crl' });
|
await page.visit({ backend: path, section: 'crl' });
|
||||||
assert.equal(currentRouteName(), 'vault.cluster.settings.configure-secret-backend.section');
|
assert.equal(currentRouteName(), 'vault.cluster.settings.configure-secret-backend.section');
|
||||||
|
|
||||||
await page.form.fillInField('time', 3);
|
await page.form.fillInValue(3);
|
||||||
await page.form.fillInField('unit', 'h');
|
await page.form.fillInUnit('h');
|
||||||
await page.form.submit();
|
await page.form.submit();
|
||||||
assert.equal(page.lastMessage, 'The crl config for this backend has been updated.');
|
assert.equal(page.lastMessage, 'The crl config for this backend has been updated.');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ module('Acceptance | settings/mount-secret-backend', function(hooks) {
|
|||||||
const maxTTLSeconds = maxTTLHours * 60 * 60;
|
const maxTTLSeconds = maxTTLHours * 60 * 60;
|
||||||
|
|
||||||
await page.visit();
|
await page.visit();
|
||||||
|
|
||||||
assert.equal(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');
|
assert.equal(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');
|
||||||
await page.selectType('kv');
|
await page.selectType('kv');
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.next()
|
.next()
|
||||||
.path(path)
|
.path(path)
|
||||||
@@ -32,6 +34,7 @@ module('Acceptance | settings/mount-secret-backend', function(hooks) {
|
|||||||
.maxTTLVal(maxTTLHours)
|
.maxTTLVal(maxTTLHours)
|
||||||
.maxTTLUnit('h')
|
.maxTTLUnit('h')
|
||||||
.submit();
|
.submit();
|
||||||
|
|
||||||
await configPage.visit({ backend: path });
|
await configPage.visit({ backend: path });
|
||||||
assert.equal(configPage.defaultTTL, defaultTTLSeconds, 'shows the proper TTL');
|
assert.equal(configPage.defaultTTL, defaultTTLSeconds, 'shows the proper TTL');
|
||||||
assert.equal(configPage.maxTTL, maxTTLSeconds, 'shows the proper max TTL');
|
assert.equal(configPage.maxTTL, maxTTLSeconds, 'shows the proper max TTL');
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ module('Integration | Component | http-requests-container', function(hooks) {
|
|||||||
await render(hbs`<HttpRequestsContainer @counters={{counters}}/>`);
|
await render(hbs`<HttpRequestsContainer @counters={{counters}}/>`);
|
||||||
|
|
||||||
assert.dom('.http-requests-container').exists();
|
assert.dom('.http-requests-container').exists();
|
||||||
assert.dom('.http-requests-dropdown').exists();
|
assert.dom('.select').exists();
|
||||||
assert.dom('.http-requests-bar-chart-container').exists();
|
assert.dom('.http-requests-bar-chart-container').exists();
|
||||||
assert.dom('.http-requests-table').exists();
|
assert.dom('.http-requests-table').exists();
|
||||||
});
|
});
|
||||||
@@ -43,7 +43,7 @@ module('Integration | Component | http-requests-container', function(hooks) {
|
|||||||
|
|
||||||
test('it filters the data according to the dropdown', async function(assert) {
|
test('it filters the data according to the dropdown', async function(assert) {
|
||||||
await render(hbs`<HttpRequestsContainer @counters={{counters}}/>`);
|
await render(hbs`<HttpRequestsContainer @counters={{counters}}/>`);
|
||||||
await fillIn('[data-test-timewindow-select]', '2018');
|
await fillIn('[data-test-select="requests-timewindow"]', '2018');
|
||||||
|
|
||||||
assert.dom('.shadow-bars> .bar').exists({ count: 1 }, 'filters the bar chart to the selected year');
|
assert.dom('.shadow-bars> .bar').exists({ count: 1 }, 'filters the bar chart to the selected year');
|
||||||
assert.dom('.start-time').exists({ count: 1 }, 'filters the table to the selected year');
|
assert.dom('.start-time').exists({ count: 1 }, 'filters the table to the selected year');
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupRenderingTest } from 'ember-qunit';
|
|
||||||
import { render } from '@ember/test-helpers';
|
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
|
||||||
|
|
||||||
const COUNTERS = [
|
|
||||||
{ start_time: '2018-04-01T00:00:00Z', total: 5500 },
|
|
||||||
{ start_time: '2019-05-01T00:00:00Z', total: 4500 },
|
|
||||||
{ start_time: '2019-06-01T00:00:00Z', total: 5000 },
|
|
||||||
];
|
|
||||||
|
|
||||||
module('Integration | Component | http-requests-dropdown', function(hooks) {
|
|
||||||
setupRenderingTest(hooks);
|
|
||||||
|
|
||||||
hooks.beforeEach(function() {
|
|
||||||
this.set('counters', COUNTERS);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it renders with options', async function(assert) {
|
|
||||||
await render(hbs`<HttpRequestsDropdown @counters={{counters}} />`);
|
|
||||||
|
|
||||||
assert.dom('[data-test-date-range]').hasValue('All', 'shows all data by default');
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
this.element.querySelector('[data-test-date-range]').options.length,
|
|
||||||
4,
|
|
||||||
'it adds an option for each year in the data set'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
77
ui/tests/integration/components/select-test.js
Normal file
77
ui/tests/integration/components/select-test.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { render, fillIn } from '@ember/test-helpers';
|
||||||
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
const OPTIONS = ['foo', 'bar', 'baz'];
|
||||||
|
const LABEL = 'Boop';
|
||||||
|
|
||||||
|
module('Integration | Component | Select', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
hooks.beforeEach(function() {
|
||||||
|
this.set('options', OPTIONS);
|
||||||
|
this.set('label', LABEL);
|
||||||
|
this.set('name', 'foo');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders', async function(assert) {
|
||||||
|
await render(hbs`<Select @options={{options}} @label={{label}} @name={{name}}/>`);
|
||||||
|
assert.dom('[data-test-select-label]').hasText('Boop');
|
||||||
|
assert.dom('[data-test-select="foo"]').exists();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders when options is an array of strings', async function(assert) {
|
||||||
|
await render(hbs`<Select @options={{options}} @label={{label}} @name={{name}}/>`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-select="foo"]').hasValue('foo');
|
||||||
|
assert.equal(this.element.querySelector('[data-test-select="foo"]').options.length, 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders when options is an array of objects', async function(assert) {
|
||||||
|
const objectOptions = [{ value: 'berry', label: 'Berry' }, { value: 'cherry', label: 'Cherry' }];
|
||||||
|
this.set('options', objectOptions);
|
||||||
|
await render(hbs`<Select @options={{options}} @label={{label}} @name={{name}}/>`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-select="foo"]').hasValue('berry');
|
||||||
|
assert.equal(this.element.querySelector('[data-test-select="foo"]').options.length, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders when options is an array of custom objects', async function(assert) {
|
||||||
|
const objectOptions = [{ day: 'mon', fullDay: 'Monday' }, { day: 'tues', fullDay: 'Tuesday' }];
|
||||||
|
const selectedValue = objectOptions[1].day;
|
||||||
|
this.setProperties({
|
||||||
|
options: objectOptions,
|
||||||
|
valueAttribute: 'day',
|
||||||
|
labelAttribute: 'fullDay',
|
||||||
|
selectedValue: selectedValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
await render(
|
||||||
|
hbs`
|
||||||
|
<Select
|
||||||
|
@options={{options}}
|
||||||
|
@label={{label}}
|
||||||
|
@name={{name}}
|
||||||
|
@valueAttribute={{valueAttribute}}
|
||||||
|
@labelAttribute={{labelAttribute}}
|
||||||
|
@selectedValue={{selectedValue}}/>`
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.dom('[data-test-select="foo"]').hasValue('tues', 'sets selectedValue by default');
|
||||||
|
assert.equal(
|
||||||
|
this.element.querySelector('[data-test-select="foo"]').options[1].textContent.trim(),
|
||||||
|
'Tuesday',
|
||||||
|
'uses the labelAttribute to determine the label'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it calls onChange when an item is selected', async function(assert) {
|
||||||
|
this.set('onChange', sinon.spy());
|
||||||
|
await render(hbs`<Select @options={{options}} @name={{name}} @onChange={{onChange}}/>`);
|
||||||
|
await fillIn('[data-test-select="foo"]', 'bar');
|
||||||
|
|
||||||
|
assert.ok(this.onChange.calledOnce);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -40,12 +40,12 @@ module('Integration | Component | wrap ttl', function(hooks) {
|
|||||||
await fillIn('[data-test-wrap-ttl-picker] input', '20');
|
await fillIn('[data-test-wrap-ttl-picker] input', '20');
|
||||||
assert.equal(this.lastOnChangeCall, '20m', 'calls onChange correctly on time input');
|
assert.equal(this.lastOnChangeCall, '20m', 'calls onChange correctly on time input');
|
||||||
|
|
||||||
await fillIn('#unit', 'h');
|
await fillIn('[data-test-select="ttl-unit"]', 'h');
|
||||||
await blur('#unit');
|
await blur('[data-test-select="ttl-unit"]');
|
||||||
assert.equal(this.lastOnChangeCall, '20h', 'calls onChange correctly on unit change');
|
assert.equal(this.lastOnChangeCall, '20h', 'calls onChange correctly on unit change');
|
||||||
|
|
||||||
await fillIn('#unit', 'd');
|
await fillIn('[data-test-select="ttl-unit"]', 'd');
|
||||||
await blur('#unit');
|
await blur('[data-test-select="ttl-unit"]');
|
||||||
assert.equal(this.lastOnChangeCall, '480h', 'converts days to hours correctly');
|
assert.equal(this.lastOnChangeCall, '480h', 'converts days to hours correctly');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export default {
|
|||||||
name: text(),
|
name: text(),
|
||||||
link: clickable('[data-test-auth-method-link]'),
|
link: clickable('[data-test-auth-method-link]'),
|
||||||
}),
|
}),
|
||||||
selectMethod: fillable('[data-test-method-select]'),
|
selectMethod: fillable('[data-test-select=auth-method]'),
|
||||||
username: fillable('[data-test-username]'),
|
username: fillable('[data-test-username]'),
|
||||||
token: fillable('[data-test-token]'),
|
token: fillable('[data-test-token]'),
|
||||||
tokenValue: value('[data-test-token]'),
|
tokenValue: value('[data-test-token]'),
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ export default {
|
|||||||
hasTitle: isPresent('[data-test-title]'),
|
hasTitle: isPresent('[data-test-title]'),
|
||||||
hasError: isPresent('[data-test-error]'),
|
hasError: isPresent('[data-test-error]'),
|
||||||
submit: clickable('[data-test-submit]'),
|
submit: clickable('[data-test-submit]'),
|
||||||
fillInField: fillable('[data-test-field]'),
|
fillInValue: fillable('[data-test-ttl-value]'),
|
||||||
|
fillInUnit: fillable('[data-test-select="ttl-unit"]'),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ export default create({
|
|||||||
certificate: text('[data-test-row-value="Certificate"]'),
|
certificate: text('[data-test-row-value="Certificate"]'),
|
||||||
toggleOptions: clickable('[data-test-toggle-group]'),
|
toggleOptions: clickable('[data-test-toggle-group]'),
|
||||||
hasCert: isPresent('[data-test-row-value="Certificate"]'),
|
hasCert: isPresent('[data-test-row-value="Certificate"]'),
|
||||||
fillInField: fillable('[data-test-field]'),
|
fillInField: fillable('[data-test-select="ttl-unit"]'),
|
||||||
issueCert: async function(commonName) {
|
issueCert: async function(commonName) {
|
||||||
await this.commonName(commonName)
|
await this.commonName(commonName)
|
||||||
.toggleOptions()
|
.toggleOptions()
|
||||||
.fillInField('unit', 'h')
|
.fillInField('h')
|
||||||
.submit();
|
.submit();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ export default create({
|
|||||||
return this.csr(csr)
|
return this.csr(csr)
|
||||||
.commonName(commonName)
|
.commonName(commonName)
|
||||||
.toggleOptions()
|
.toggleOptions()
|
||||||
.fillInField('unit', 'h')
|
.fillInField('h')
|
||||||
.submit();
|
.submit();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ export default create({
|
|||||||
...mountForm,
|
...mountForm,
|
||||||
version: fillable('[data-test-input="options.version"]'),
|
version: fillable('[data-test-input="options.version"]'),
|
||||||
maxTTLVal: fillable('[data-test-input="config.maxLeaseTtl"] [data-test-ttl-value]'),
|
maxTTLVal: fillable('[data-test-input="config.maxLeaseTtl"] [data-test-ttl-value]'),
|
||||||
maxTTLUnit: fillable('[data-test-input="config.maxLeaseTtl"] [data-test-ttl-unit]'),
|
maxTTLUnit: fillable('[data-test-input="config.maxLeaseTtl"] [data-test-select="ttl-unit"]'),
|
||||||
defaultTTLVal: fillable('[data-test-input="config.defaultLeaseTtl"] [data-test-ttl-value]'),
|
defaultTTLVal: fillable('[data-test-input="config.defaultLeaseTtl"] [data-test-ttl-value]'),
|
||||||
defaultTTLUnit: fillable('[data-test-input="config.defaultLeaseTtl"] [data-test-ttl-unit]'),
|
defaultTTLUnit: fillable('[data-test-input="config.defaultLeaseTtl"] [data-test-select="ttl-unit"]'),
|
||||||
enable: async function(type, path) {
|
enable: async function(type, path) {
|
||||||
await this.visit();
|
await this.visit();
|
||||||
await this.mount(type, path);
|
await this.mount(type, path);
|
||||||
|
|||||||
Reference in New Issue
Block a user