KV automatic delete state issue in UI (#13166)
* converts secret-v2-version model to native class -- fixes issues with cached values for deleted prop * adds changelog entry * adds disabled state to ToolbarLink component and disables create new version action when users cannot read metadata * updates secret-edit acceptance test
This commit is contained in:
parent
201526e983
commit
516f18f736
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:bug
|
||||||
|
ui: Fixes issue with placeholder not displaying for automatically deleted secrets when deletion time has passed
|
||||||
|
```
|
|
@ -1,20 +1,21 @@
|
||||||
import { belongsTo, attr } from '@ember-data/model';
|
import { belongsTo, attr } from '@ember-data/model';
|
||||||
import Secret from './secret';
|
import SecretModel from './secret';
|
||||||
import { computed } from '@ember/object';
|
|
||||||
|
|
||||||
export default Secret.extend({
|
export default class SecretV2VersionModel extends SecretModel {
|
||||||
failedServerRead: attr('boolean'),
|
@attr('boolean') failedServerRead;
|
||||||
pathAttr: 'path',
|
@attr('number') version;
|
||||||
version: attr('number'),
|
@attr('string') path;
|
||||||
secret: belongsTo('secret-v2'),
|
@attr('string') deletionTime;
|
||||||
path: attr('string'),
|
@attr('string') createdTime;
|
||||||
deletionTime: attr('string'),
|
@attr('boolean') detroyed;
|
||||||
createdTime: attr('string'),
|
@attr('number') currentVersion;
|
||||||
deleted: computed('deletionTime', function() {
|
@belongsTo('secret-v2') secret;
|
||||||
|
|
||||||
|
pathAttr = 'path';
|
||||||
|
|
||||||
|
get deleted() {
|
||||||
const deletionTime = new Date(this.deletionTime);
|
const deletionTime = new Date(this.deletionTime);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
return deletionTime <= now;
|
return deletionTime <= now;
|
||||||
}),
|
}
|
||||||
destroyed: attr('boolean'),
|
}
|
||||||
currentVersion: attr('number'),
|
|
||||||
});
|
|
||||||
|
|
|
@ -155,12 +155,9 @@ export default Route.extend(UnloadModelRoute, {
|
||||||
try {
|
try {
|
||||||
if (secretModel.failedServerRead) {
|
if (secretModel.failedServerRead) {
|
||||||
// we couldn't read metadata, so we want to directly fetch the version
|
// we couldn't read metadata, so we want to directly fetch the version
|
||||||
|
versionModel = await this.store.findRecord('secret-v2-version', JSON.stringify(versionId), {
|
||||||
versionModel =
|
reload: true,
|
||||||
this.store.peekRecord('secret-v2-version', JSON.stringify(versionId)) ||
|
});
|
||||||
(await this.store.findRecord('secret-v2-version', JSON.stringify(versionId), {
|
|
||||||
reload: true,
|
|
||||||
}));
|
|
||||||
} else {
|
} else {
|
||||||
// we may have previously errored, so roll it back here
|
// we may have previously errored, so roll it back here
|
||||||
version.rollbackAttributes();
|
version.rollbackAttributes();
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
color: $black;
|
color: $black;
|
||||||
transition: background-color $speed;
|
transition: background-color $speed;
|
||||||
|
|
||||||
&:hover {
|
&:hover:not(.disabled) {
|
||||||
background-color: $ui-gray-100;
|
background-color: $ui-gray-100;
|
||||||
border: 0;
|
border: 0;
|
||||||
color: $blue;
|
color: $blue;
|
||||||
|
@ -98,6 +98,18 @@
|
||||||
height: 2.5rem;
|
height: 2.5rem;
|
||||||
padding: $size-10 $size-8;
|
padding: $size-10 $size-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-separator {
|
.toolbar-separator {
|
||||||
|
|
|
@ -101,6 +101,8 @@
|
||||||
@data-test-secret-edit="true"
|
@data-test-secret-edit="true"
|
||||||
@replace={{true}}
|
@replace={{true}}
|
||||||
@type="add"
|
@type="add"
|
||||||
|
@disabled={{@model.failedServerRead}}
|
||||||
|
@disabledTooltip="Metadata read access is required to create new version"
|
||||||
>
|
>
|
||||||
Create new version
|
Create new version
|
||||||
</ToolbarLink>
|
</ToolbarLink>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"allowJs": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
|
@ -7,15 +7,17 @@
|
||||||
* ```js
|
* ```js
|
||||||
* <Toolbar>
|
* <Toolbar>
|
||||||
* <ToolbarActions>
|
* <ToolbarActions>
|
||||||
* <ToolbarLink @params={{array 'vault.cluster.policies.create'}} @type="add">
|
* <ToolbarLink @params={{array 'vault.cluster.policies.create'}} @type="add" @disabled={{true}} @disabledTooltip="This link is disabled">
|
||||||
* Create policy
|
* Create policy
|
||||||
* </ToolbarLink>
|
* </ToolbarLink>
|
||||||
* </ToolbarActions>
|
* </ToolbarActions>
|
||||||
* </Toolbar>
|
* </Toolbar>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param params=''{Array} Array to pass to LinkTo
|
* @param {array} params - Array to pass to LinkTo
|
||||||
* @param type=''{String} Use "add" to change icon
|
* @param {string} type - Use "add" to change icon
|
||||||
|
* @param {boolean} disabled - pass true to disable link
|
||||||
|
* @param {string} disabledTooltip - tooltip to display on hover when disabled
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
@ -27,6 +29,8 @@ export default Component.extend({
|
||||||
tagName: '',
|
tagName: '',
|
||||||
supportsDataTestProperties: true,
|
supportsDataTestProperties: true,
|
||||||
type: null,
|
type: null,
|
||||||
|
disabled: false,
|
||||||
|
disabledTooltip: null,
|
||||||
glyph: computed('type', function() {
|
glyph: computed('type', function() {
|
||||||
if (this.type == 'add') {
|
if (this.type == 'add') {
|
||||||
return 'plus-plain';
|
return 'plus-plain';
|
||||||
|
|
|
@ -1,20 +1,36 @@
|
||||||
<LinkTo
|
{{#let (component "link-to"
|
||||||
class="toolbar-link"
|
class="toolbar-link"
|
||||||
@params={{params}}
|
disabled=disabled
|
||||||
data-test-secret-edit={{data-test-secret-edit}}
|
params=params
|
||||||
data-test-secondary-add={{data-test-secondary-add}}
|
data-test-secret-edit=data-test-secret-edit
|
||||||
data-test-configure-link={{data-test-configure-link}}
|
data-test-secondary-add=data-test-secondary-add
|
||||||
data-test-alias-edit-link={{data-test-alias-edit-link}}
|
data-test-configure-link=data-test-configure-link
|
||||||
data-test-entity-edit-link={{data-test-entity-edit-link}}
|
data-test-alias-edit-link=data-test-alias-edit-link
|
||||||
data-test-replication-link={{data-test-replication-link}}
|
data-test-entity-edit-link=data-test-entity-edit-link
|
||||||
data-test-entity-merge-link={{data-test-entity-merge-link}}
|
data-test-replication-link=data-test-replication-link
|
||||||
data-test-backend-view-link={{data-test-backend-view-link}}
|
data-test-entity-merge-link=data-test-entity-merge-link
|
||||||
data-test-entity-create-link={{data-test-entity-create-link}}
|
data-test-backend-view-link=data-test-backend-view-link
|
||||||
data-test-policy-create-link={{data-test-policy-create-link}}
|
data-test-entity-create-link=data-test-entity-create-link
|
||||||
data-test-policy-edit-toggle={{data-test-policy-edit-toggle}}
|
data-test-policy-create-link=data-test-policy-create-link
|
||||||
data-test-secret-backend-configure={{data-test-secret-backend-configure}}
|
data-test-policy-edit-toggle=data-test-policy-edit-toggle
|
||||||
...attributes
|
data-test-secret-backend-configure=data-test-secret-backend-configure
|
||||||
>
|
) as |LinkToComponent|}}
|
||||||
{{yield}}
|
{{#if (and disabled disabledTooltip)}}
|
||||||
<Icon @glyph={{glyph}} />
|
<ToolTip @verticalPosition="above" as |T|>
|
||||||
</LinkTo>
|
<T.trigger tabindex="-1">
|
||||||
|
<LinkToComponent ...attributes>
|
||||||
|
{{yield}} <Icon @glyph={{glyph}} data-test-icon={{glyph}} />
|
||||||
|
</LinkToComponent>
|
||||||
|
</T.trigger>
|
||||||
|
<T.content @class="tool-tip smaller-font">
|
||||||
|
<div class="box" data-test-disabled-tooltip>
|
||||||
|
{{disabledTooltip}}
|
||||||
|
</div>
|
||||||
|
</T.content>
|
||||||
|
</ToolTip>
|
||||||
|
{{else}}
|
||||||
|
<LinkToComponent ...attributes>
|
||||||
|
{{yield}} <Icon @glyph={{glyph}} data-test-icon={{glyph}} />
|
||||||
|
</LinkToComponent>
|
||||||
|
{{/if}}
|
||||||
|
{{/let}}
|
||||||
|
|
|
@ -4,18 +4,21 @@
|
||||||
`ToolbarLink` components style links and buttons for the Toolbar
|
`ToolbarLink` components style links and buttons for the Toolbar
|
||||||
It should only be used inside of `Toolbar`.
|
It should only be used inside of `Toolbar`.
|
||||||
|
|
||||||
|
**Params**
|
||||||
|
|
||||||
| Param | Type | Default | Description |
|
| Param | Type | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| params | <code>Array</code> | <code>''</code> | Array to pass to LinkTo |
|
| params | <code>array</code> | Array to pass to LinkTo |
|
||||||
| type | <code>String</code> | <code>''</code> | Use "add" to change icon |
|
| type | <code>string</code> | Use "add" to change icon |
|
||||||
|
| disabled | <code>boolean</code> | pass true to disable link |
|
||||||
|
| disabledTooltip | <code>string</code> | tooltip to display on hover when disabled |
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
```js
|
```js
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<ToolbarActions>
|
<ToolbarActions>
|
||||||
<ToolbarLink @params={{array 'vault.cluster.policies.create'}} @type="add">
|
<ToolbarLink @params={{array 'vault.cluster.policies.create'}} @type="add" @disabled={{true}} @disabledTooltip="This link is disabled">
|
||||||
Create policy
|
Create policy
|
||||||
</ToolbarLink>
|
</ToolbarLink>
|
||||||
</ToolbarActions>
|
</ToolbarActions>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
import { storiesOf } from '@storybook/ember';
|
import { storiesOf } from '@storybook/ember';
|
||||||
import { withKnobs, select, text } from '@storybook/addon-knobs';
|
import { withKnobs, select, text, boolean } from '@storybook/addon-knobs';
|
||||||
import notes from './toolbar-link.md';
|
import notes from './toolbar-link.md';
|
||||||
|
|
||||||
storiesOf('Toolbar', module)
|
storiesOf('Toolbar', module)
|
||||||
|
@ -17,6 +17,8 @@ storiesOf('Toolbar', module)
|
||||||
<ToolbarLink
|
<ToolbarLink
|
||||||
@params={{array '#'}}
|
@params={{array '#'}}
|
||||||
@type={{type}}
|
@type={{type}}
|
||||||
|
@disabled={{disabled}}
|
||||||
|
@disabledTooltip={{disabledTooltip}}
|
||||||
>
|
>
|
||||||
{{label}}
|
{{label}}
|
||||||
</ToolbarLink>
|
</ToolbarLink>
|
||||||
|
@ -27,6 +29,8 @@ storiesOf('Toolbar', module)
|
||||||
context: {
|
context: {
|
||||||
type: select('Type', ['', 'add']),
|
type: select('Type', ['', 'add']),
|
||||||
label: text('Button text', 'Edit secret'),
|
label: text('Button text', 'Edit secret'),
|
||||||
|
disabled: boolean('disabled', false),
|
||||||
|
disabledTooltip: text('Tooltip to display when disabled', ''),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
{ notes }
|
{ notes }
|
||||||
|
|
|
@ -617,13 +617,8 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
||||||
await assert
|
await assert
|
||||||
.dom('[data-test-value-div="secret-key"]')
|
.dom('[data-test-value-div="secret-key"]')
|
||||||
.exists('secret view page and info table row with secret-key value');
|
.exists('secret view page and info table row with secret-key value');
|
||||||
// check you can create new version
|
// create new version should be disabled with no metadata read access
|
||||||
await click('[data-test-secret-edit="true"]');
|
assert.dom('[data-test-secret-edit]').hasClass('disabled', 'Create new version action is disabled');
|
||||||
await settled();
|
|
||||||
await fillIn('[data-test-secret-key]', 'version2');
|
|
||||||
await editPage.save();
|
|
||||||
await settled();
|
|
||||||
assert.dom('[data-test-row-label="version2"]').exists('the current version displayed is the new version');
|
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-popup-menu-trigger="version"]')
|
.dom('[data-test-popup-menu-trigger="version"]')
|
||||||
.doesNotExist('the version drop down menu does not show');
|
.doesNotExist('the version drop down menu does not show');
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupRenderingTest } from 'ember-qunit';
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
import { render } from '@ember/test-helpers';
|
import { render, triggerEvent } from '@ember/test-helpers';
|
||||||
import { isPresent } from 'ember-cli-page-object';
|
import { isPresent } from 'ember-cli-page-object';
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
|
||||||
|
@ -14,4 +14,41 @@ module('Integration | Component | toolbar-link', function(hooks) {
|
||||||
assert.ok(isPresent('.toolbar-link'));
|
assert.ok(isPresent('.toolbar-link'));
|
||||||
assert.ok(isPresent('.icon'));
|
assert.ok(isPresent('.icon'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('it should render icons', async function(assert) {
|
||||||
|
assert.expect(2);
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
<ToolbarLink
|
||||||
|
@params={{array '/secrets'}}
|
||||||
|
@type={{this.type}}
|
||||||
|
>
|
||||||
|
Test Link
|
||||||
|
</ToolbarLink>
|
||||||
|
`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-icon="chevron-right"]').exists('Default chevron right icon renders');
|
||||||
|
this.set('type', 'add');
|
||||||
|
assert.dom('[data-test-icon="plus-plain"]').exists('Icon can be overriden to show plus sign');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it should disable and show tooltip if provided', async function(assert) {
|
||||||
|
assert.expect(3);
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
<ToolbarLink
|
||||||
|
@params={{array '/secrets'}}
|
||||||
|
@disabled={{true}}
|
||||||
|
@disabledTooltip={{this.tooltip}}
|
||||||
|
>
|
||||||
|
Test Link
|
||||||
|
</ToolbarLink>
|
||||||
|
`);
|
||||||
|
|
||||||
|
assert.dom('a').hasClass('disabled', 'Link can be disabled');
|
||||||
|
assert.dom('[data-test-popup-menu-trigger]').doesNotExist('Tooltip is hidden when not provided');
|
||||||
|
this.set('tooltip', 'Test tooltip');
|
||||||
|
await triggerEvent('.ember-basic-dropdown-trigger', 'mouseenter');
|
||||||
|
assert.dom('[data-test-disabled-tooltip]').hasText(this.tooltip, 'Tooltip renders');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue