Skip to content

Commit

Permalink
UI - identity details (#4502)
Browse files Browse the repository at this point in the history
* add popups
* add ability to disable entity and banner when entity is disabled
* re-add alias-popup template
* add accpetance tests for creating entities
* add more entity creation acceptance tests
* add delete to edit-form
* add more identity tests and associated selectors
* add onSuccess hook and use UnloadModel route mixins
* add ability to toggle entity disabling from the popover
* fix store list cache because unloadAll isn't synchronous
* fill out tests for identity items and aliases
* add ability to enable entity from the detail page
* toArray on the peekAll
* fix other tests/behavior that relied on a RecordArray
* adjust layout for disabled entity and label for disabling an entity on the edit form
* add item-details integration tests
* move disable field on the entity form
* use ghost buttons for delete in identity and policy edit forms
* adding computed macros for lazy capability fetching and using them in the identity models
  • Loading branch information
meirish authored May 24, 2018
1 parent 70434e2 commit 3bc90ac
Show file tree
Hide file tree
Showing 85 changed files with 1,426 additions and 220 deletions.
1 change: 1 addition & 0 deletions ui/app/components/confirm-action.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default Ember.Component.extend({
class={{buttonClasses}}
type="button"
disabled={{disabled}}
data-test-confirm-action-trigger=true
{{action 'toggleConfirm'}}
>
{{yield}}
Expand Down
40 changes: 40 additions & 0 deletions ui/app/components/identity/_popup-base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Ember from 'ember';
const { assert, inject, Component } = Ember;

export default Component.extend({
tagName: '',
flashMessages: inject.service(),
params: null,
successMessage() {
return 'Save was successful';
},
errorMessage() {
return 'There was an error saving';
},
onError(model) {
if (model && model.rollbackAttributes) {
model.rollbackAttributes();
}
},
onSuccess(){},
// override and return a promise
transaction() {
assert('override transaction call in an extension of popup-base', false);
},

actions: {
performTransaction() {
let args = [...arguments];
let messageArgs = this.messageArgs(...args);
return this.transaction(...args)
.then(() => {
this.get('onSuccess')();
this.get('flashMessages').success(this.successMessage(...messageArgs));
})
.catch(e => {
this.onError(...messageArgs);
this.get('flashMessages').success(this.errorMessage(e, ...messageArgs));
});
},
},
});
35 changes: 26 additions & 9 deletions ui/app/components/identity/edit-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@ import Ember from 'ember';
import { task } from 'ember-concurrency';
import { humanize } from 'vault/helpers/humanize';

const { computed } = Ember;
const { computed, inject } = Ember;
export default Ember.Component.extend({
flashMessages: inject.service(),
'data-test-component': 'identity-edit-form',
model: null,

// 'create', 'edit', 'merge'
mode: 'create',
/*
* @param Function
* @public
*
* Optional param to call a function upon successfully mounting a backend
*
* Optional param to call a function upon successfully saving an entity
*/
onSave: () => {},

cancelLink: computed('mode', 'model', function() {
cancelLink: computed('mode', 'model.identityType', function() {
let { model, mode } = this.getProperties('model', 'mode');
let key = `${mode}-${model.get('identityType')}`;
let routes = {
Expand All @@ -33,16 +36,17 @@ export default Ember.Component.extend({
return routes[key];
}),

getMessage(model) {
getMessage(model, isDelete = false) {
let mode = this.get('mode');
let typeDisplay = humanize([model.get('identityType')]);
let action = isDelete ? 'deleted' : 'saved';
if (mode === 'merge') {
return 'Successfully merged entities';
}
if (model.get('id')) {
return `Successfully saved ${typeDisplay} ${model.id}.`;
return `Successfully ${action} ${typeDisplay} ${model.id}.`;
}
return `Successfully saved ${typeDisplay}.`;
return `Successfully ${action} ${typeDisplay}.`;
},

save: task(function*() {
Expand All @@ -56,13 +60,26 @@ export default Ember.Component.extend({
return;
}
this.get('flashMessages').success(message);
yield this.get('onSave')(model);
yield this.get('onSave')({saveType: 'save', model});
}).drop(),

willDestroy() {
let model = this.get('model');
if (!model.isDestroyed || !model.isDestroying) {
if ((model.get('isDirty') && !model.isDestroyed) || !model.isDestroying) {
model.rollbackAttributes();
}
},

actions: {
deleteItem(model) {
let message = this.getMessage(model, true);
let flash = this.get('flashMessages');
model
.destroyRecord()
.then(() => {
flash.success(message);
return this.get('onSave')({saveType: 'delete', model});
});
},
},
});
23 changes: 23 additions & 0 deletions ui/app/components/identity/item-details.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Ember from 'ember';

const { inject } = Ember;

export default Ember.Component.extend({
flashMessages: inject.service(),

actions: {
enable(model) {
model.set('disabled', false);

model.save().
then(() => {
this.get('flashMessages').success(`Successfully enabled entity: ${model.id}`);
})
.catch(e => {
this.get('flashMessages').success(
`There was a problem enabling the entity: ${model.id} - ${e.error.join(' ') || e.message}`
);
});
}
}
});
22 changes: 22 additions & 0 deletions ui/app/components/identity/popup-alias.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Base from './_popup-base';

export default Base.extend({
messageArgs(model) {
let type = model.get('identityType');
let id = model.id;
return [type, id];
},

successMessage(type, id) {
return `Successfully deleted ${type}: ${id}`;
},

errorMessage(e, type, id) {
let error = e.errors ? e.errors.join(' ') : e.message;
return `There was a problem deleting ${type}: ${id} - ${error}`;
},

transaction(model) {
return model.destroyRecord();
},
});
34 changes: 34 additions & 0 deletions ui/app/components/identity/popup-members.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Base from './_popup-base';
import Ember from 'ember';
const { computed } = Ember;

export default Base.extend({
model: computed.alias('params.firstObject'),

groupArray: computed('params', function() {
return this.get('params').objectAt(1);
}),

memberId: computed('params', function() {
return this.get('params').objectAt(2);
}),

messageArgs(/*model, groupArray, memberId*/) {
return [...arguments];
},

successMessage(model, groupArray, memberId) {
return `Successfully removed '${memberId}' from the group`;
},

errorMessage(e, model, groupArray, memberId) {
let error = e.errors ? e.errors.join(' ') : e.message;
return `There was a problem removing '${memberId}' from the group - ${error}`;
},

transaction(model, groupArray, memberId) {
let members = model.get(groupArray);
model.set(groupArray, members.without(memberId));
return model.save();
},
});
29 changes: 29 additions & 0 deletions ui/app/components/identity/popup-metadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Base from './_popup-base';
import Ember from 'ember';
const { computed } = Ember;

export default Base.extend({
model: computed.alias('params.firstObject'),
key: computed('params', function() {
return this.get('params').objectAt(1);
}),

messageArgs(model, key) {
return [model, key];
},

successMessage(model, key) {
return `Successfully removed '${key}' from metadata`;
},
errorMessage(e, model, key) {
let error = e.errors ? e.errors.join(' ') : e.message;
return `There was a problem removing '${key}' from the metadata - ${error}`;
},

transaction(model, key) {
let metadata = model.get('metadata');
delete metadata[key];
model.set('metadata', { ...metadata });
return model.save();
},
});
29 changes: 29 additions & 0 deletions ui/app/components/identity/popup-policy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Base from './_popup-base';
import Ember from 'ember';
const { computed } = Ember;

export default Base.extend({
model: computed.alias('params.firstObject'),
policyName: computed('params', function() {
return this.get('params').objectAt(1);
}),

messageArgs(model, policyName) {
return [model, policyName];
},

successMessage(model, policyName) {
return `Successfully removed '${policyName}' policy from ${model.id} `;
},

errorMessage(e, model, policyName) {
let error = e.errors ? e.errors.join(' ') : e.message;
return `There was a problem removing '${policyName}' policy - ${error}`;
},

transaction(model, policyName) {
let policies = model.get('policies');
model.set('policies', policies.without(policyName));
return model.save();
},
});
1 change: 1 addition & 0 deletions ui/app/components/info-table-row.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Ember from 'ember';

export default Ember.Component.extend({
'data-test-component': 'info-table-row',
classNames: ['info-table-row'],
isVisible: Ember.computed.or('alwaysRender', 'value'),

Expand Down
2 changes: 2 additions & 0 deletions ui/app/components/message-in-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const { computed } = Ember;
export default Ember.Component.extend({
type: null,

yieldWithoutColumn: false,

classNameBindings: ['containerClass'],

containerClass: computed('type', function() {
Expand Down
2 changes: 0 additions & 2 deletions ui/app/components/secret-list-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@ export default Ember.Component.extend({
baseKey: null,
backendCrumb: null,
model: null,


});
2 changes: 1 addition & 1 deletion ui/app/components/tool-actions-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default Ember.Component.extend(DEFAULTS, {

handleSuccess(resp, action) {
let props = {};
let secret = resp && resp.data || resp.auth;
let secret = (resp && resp.data) || resp.auth;
if (secret && action === 'unwrap') {
props = Ember.assign({}, props, { unwrap_data: secret });
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import Ember from 'ember';
import ListController from 'vault/mixins/list-controller';

export default Ember.Controller.extend(ListController);
export default Ember.Controller.extend(ListController, {
actions: {
onDelete() {
this.send('reload');
}
}
});
23 changes: 21 additions & 2 deletions ui/app/controllers/vault/cluster/access/identity/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,26 @@ import { task } from 'ember-concurrency';
export default Ember.Controller.extend({
showRoute: 'vault.cluster.access.identity.show',
showTab: 'details',
navToShow: task(function*(model) {
yield this.transitionToRoute(this.get('showRoute'), model.id, this.get('showTab'));
navAfterSave: task(function*({saveType, model}) {
let isDelete = saveType === 'delete';
let type = model.get('identityType');
let listRoutes= {
'entity-alias': 'vault.cluster.access.identity.aliases.index',
'group-alias': 'vault.cluster.access.identity.aliases.index',
'group': 'vault.cluster.access.identity.index',
'entity': 'vault.cluster.access.identity.index',
};
let routeName = listRoutes[type]
if (!isDelete) {
yield this.transitionToRoute(
this.get('showRoute'),
model.id,
this.get('showTab')
);
return;
}
yield this.transitionToRoute(
routeName
);
}),
});
44 changes: 43 additions & 1 deletion ui/app/controllers/vault/cluster/access/identity/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,46 @@
import Ember from 'ember';
import ListController from 'vault/mixins/list-controller';

export default Ember.Controller.extend(ListController);
const { inject } = Ember;

export default Ember.Controller.extend(ListController, {
flashMessages: inject.service(),

actions: {
delete(model) {
let type = model.get('identityType');
let id = model.id;
return model
.destroyRecord()
.then(() => {
this.send('reload');
this.get('flashMessages').success(`Successfully deleted ${type}: ${id}`);
})
.catch(e => {
this.get('flashMessages').success(
`There was a problem deleting ${type}: ${id} - ${e.error.join(' ') || e.message}`
);
});
},

toggleDisabled(model) {
let action = model.get('disabled') ? ['enabled', 'enabling'] : ['disabled', 'disabling'];
let type = model.get('identityType');
let id = model.id;
model.toggleProperty('disabled');

model.save().
then(() => {
this.get('flashMessages').success(`Successfully ${action[0]} ${type}: ${id}`);
})
.catch(e => {
this.get('flashMessages').success(
`There was a problem ${action[1]} ${type}: ${id} - ${e.error.join(' ') || e.message}`
);
});
},
reloadRecord(model) {
model.reload();
},
},
});
Loading

0 comments on commit 3bc90ac

Please sign in to comment.