use model dirty tracking to track changes

This commit is contained in:
Matthew Irish 2018-10-15 09:38:05 -05:00
parent e5ff92962d
commit 077f366954
9 changed files with 65 additions and 41 deletions

View File

@ -74,13 +74,6 @@ export default Component.extend(FocusOnInsertMixin, {
}
},
willDestroyElement() {
this._super(...arguments);
if (this.model.isError && !this.model.isDestroyed) {
this.model.rollbackAttributes();
}
},
waitForKeyUp: task(function*() {
while (true) {
let event = yield waitForEvent(document.body, 'keyup');
@ -115,6 +108,25 @@ export default Component.extend(FocusOnInsertMixin, {
canDelete: alias('updatePath.canDelete'),
canEdit: alias('updatePath.canUpdate'),
v2UpdatePath: queryRecord(
'capabilities',
context => {
if (context.mode === 'create' || context.isV2 === false) {
return {};
}
let backend = context.model.belongsTo('engine').id;
let id = context.model.id;
return {
id: `${backend}/metadata/${id}`,
};
},
'isV2',
'model',
'model.id',
'mode'
),
canEditV2Secret: alias('updatePath.canUpdate'),
requestInFlight: or('model.isLoading', 'model.isReloading', 'model.isSaving'),
buttonDisabled: or(
@ -164,7 +176,9 @@ export default Component.extend(FocusOnInsertMixin, {
// successCallback is called in the context of the component
persistKey(successCallback) {
let secret = this.model;
let model = this.modelForData;
let isV2 = this.isV2;
let key = model.get('path') || model.id;
if (key.startsWith('/')) {
@ -174,13 +188,28 @@ export default Component.extend(FocusOnInsertMixin, {
return model.save().then(() => {
if (!model.isError) {
if (this.wizard.featureState === 'secret') {
this.wizard.transitionFeatureMachine('secret', 'CONTINUE');
if (isV2 && Object.keys(secret.changedAttributes()).length) {
// save secret metadata
secret
.save()
.then(() => {
this.saveComplete(successCallback, key);
})
.catch(e => {
this.set(e, e.errors.join(' '));
});
} else {
this.saveComplete(successCallback, key);
}
successCallback(key);
}
});
},
saveComplete(callback, key) {
if (this.wizard.featureState === 'secret') {
this.wizard.transitionFeatureMachine('secret', 'CONTINUE');
}
callback(key);
},
checkRows() {
if (this.secretData.length === 0) {
@ -203,14 +232,11 @@ export default Component.extend(FocusOnInsertMixin, {
handleChange() {
this.set('codemirrorString', this.secretData.toJSONString(true));
this.modelForData.set('secretData', this.secretData.toJSON());
},
createOrUpdateKey(type, event) {
event.preventDefault();
const newData = this.secretData.toJSON();
let model = this.modelForData;
model.set('secretData', newData);
// prevent from submitting if there's no key
// maybe do something fancier later
if (type === 'create' && isBlank(model.get('path') || model.id)) {
@ -241,7 +267,7 @@ export default Component.extend(FocusOnInsertMixin, {
const data = this.secretData;
if (isNone(data.findBy('name', ''))) {
data.pushObject({ name: '', value: '' });
this.set('codemirrorString', data.toJSONString(true));
this.send('handleChange');
}
this.checkRows();
},
@ -254,7 +280,7 @@ export default Component.extend(FocusOnInsertMixin, {
}
data.removeObject(item);
this.checkRows();
this.set('codemirrorString', data.toJSONString(true));
this.send('handleChange');
},
toggleAdvanced(bool) {

View File

@ -12,9 +12,5 @@ export default Controller.extend(BackendCrumbMixin, {
// so we have to manually bubble here
this.send('refreshModel');
},
hasChanges(hasChanges) {
this.send('hasDataChanges', hasChanges);
},
},
});

View File

@ -11,9 +11,6 @@ export default Controller.extend(BackendCrumbMixin, {
refresh: function() {
this.send('refreshModel');
},
hasChanges(hasChanges) {
this.send('hasDataChanges', hasChanges);
},
toggleAdvancedEdit(bool) {
this.set('preferAdvancedEdit', bool);
this.get('backendController').set('preferAdvancedEdit', bool);

View File

@ -15,10 +15,6 @@ export default Controller.extend(BackendCrumbMixin, {
this.send('refreshModel');
},
hasChanges(hasChanges) {
this.send('hasDataChanges', hasChanges);
},
toggleAdvancedEdit(bool) {
this.set('preferAdvancedEdit', bool);
this.get('backendController').set('preferAdvancedEdit', bool);

View File

@ -17,10 +17,6 @@ export default Controller.extend(BackendCrumbMixin, {
this.send('refreshModel');
},
hasChanges(hasChanges) {
this.send('hasDataChanges', hasChanges);
},
toggleAdvancedEdit(bool) {
this.set('preferAdvancedEdit', bool);
this.get('backendController').set('preferAdvancedEdit', bool);

View File

@ -1,6 +1,6 @@
import Secret from './secret';
import DS from 'ember-data';
import { bool } from '@ember/object/computed';
import { alias, bool } from '@ember/object/computed';
const { attr, belongsTo } = DS;

View File

@ -1,5 +1,7 @@
import DS from 'ember-data';
import { computed } from '@ember/object';
import { match } from '@ember/object/computed';
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
const { attr, hasMany, belongsTo, Model } = DS;
@ -11,7 +13,18 @@ export default Model.extend({
updatedTime: attr(),
currentVersion: attr('number'),
oldestVersion: attr('number'),
maxVersions: attr('number'),
casRequired: attr('boolean'),
maxVersions: attr('number', {
defaultValue: 10,
label: 'Maximum Number of Versions',
}),
casRequired: attr('boolean', {
defaultValue: false,
label: 'Require Check and Set',
helpText:
'Writes will only be allowed if the keys current version matches the version specified in the cas parameter',
}),
isFolder: match('id', /\/$/),
fields: computed(function() {
return expandAttributeMeta(this, ['maxVersions', 'casRequired']);
}),
});

View File

@ -73,6 +73,7 @@ export default Route.extend(UnloadModelRoute, {
return hash({
secret: this.store.queryRecord(modelType, { id: secret, backend }).then(resp => {
if (modelType === 'secret-v2') {
let backendModel = this.modelFor('vault.cluster.secrets.backend', backend);
let targetVersion = parseInt(params.version || resp.currentVersion, 10);
let version = resp.versions.findBy('version', targetVersion);
// 404 if there's no version
@ -81,6 +82,7 @@ export default Route.extend(UnloadModelRoute, {
set(error, 'httpStatus', 404);
throw error;
}
resp.set('engine', backendModel);
return version.reload().then(() => {
resp.set('selectedVersion', version);
@ -136,14 +138,17 @@ export default Route.extend(UnloadModelRoute, {
},
willTransition(transition) {
if (this.get('hasChanges')) {
let model = this.controller.model;
let version = model.get('selectedVersion');
debugger; //eslint-disable-line
if (model.hasDirtyAttributes || (version && version.hasDirtyAttributes)) {
if (
window.confirm(
'You have unsaved changes. Navigating away will discard these changes. Are you sure you want to discard your changes?'
)
) {
version && version.rollbackAttributes();
this.unloadModel();
this.set('hasChanges', false);
return true;
} else {
transition.abort();
@ -152,9 +157,5 @@ export default Route.extend(UnloadModelRoute, {
}
return this._super(...arguments);
},
hasDataChanges(hasChanges) {
this.set('hasChanges', hasChanges);
},
},
});

View File

@ -5,7 +5,6 @@
mode=mode
root=backendCrumb
capabilities=capabilities
onDataChange=(action "hasChanges")
onRefresh=(action "refresh")
onToggleAdvancedEdit=(action "toggleAdvancedEdit")
initialKey=initialKey