UI: Move legacy ACLs, KVs and Intentions to use form functionality (#4936)

Change legacy acls, kvs and intentions to use `form`s
This commit is contained in:
John Cowen 2018-11-19 14:53:08 +00:00 committed by John Cowen
parent d6fd3f799c
commit 5eed6dcef6
19 changed files with 133 additions and 84 deletions

View file

@ -1,30 +1,31 @@
import Controller from '@ember/controller';
import { set } from '@ember/object';
import Changeset from 'ember-changeset';
import validations from 'consul-ui/validations/acl';
import lookupValidator from 'ember-changeset-validations';
import { inject as service } from '@ember/service';
import { get } from '@ember/object';
export default Controller.extend({
builder: service('form'),
dom: service('dom'),
init: function() {
this._super(...arguments);
this.form = get(this, 'builder').form('acl');
},
setProperties: function(model) {
this.changeset = new Changeset(model.item, lookupValidator(validations), validations);
this._super({
...model,
...{
item: this.changeset,
},
});
},
actions: {
change: function(e) {
const target = e.target || { name: 'Rules', value: e };
switch (target.name) {
case 'Type':
set(this.changeset, target.name, target.value);
break;
case 'Rules':
set(this, 'item.Rules', target.value);
// essentially this replaces the data with changesets
this._super(
Object.keys(model).reduce((prev, key, i) => {
switch (key) {
case 'item':
prev[key] = this.form.setData(prev[key]).getData();
break;
}
return prev;
}, model)
);
},
actions: {
change: function(e, value, item) {
const event = get(this, 'dom').normalizeEvent(e, value);
get(this, 'form').handleEvent(event);
},
},
});

View file

@ -25,8 +25,8 @@ export default Controller.extend({
},
actions: {
change: function(e, value, item) {
const form = get(this, 'form');
const event = get(this, 'dom').normalizeEvent(e, value);
const form = get(this, 'form');
try {
form.handleEvent(event);
} catch (err) {

View file

@ -45,8 +45,8 @@ export default Controller.extend({
.didAppear();
},
change: function(e, value, item) {
const form = get(this, 'form');
const event = get(this, 'dom').normalizeEvent(e, value);
const form = get(this, 'form');
try {
form.handleEvent(event);
} catch (err) {

View file

@ -1,13 +1,15 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { get, set } from '@ember/object';
import Changeset from 'ember-changeset';
import lookupValidator from 'ember-changeset-validations';
import validations from 'consul-ui/validations/intention';
export default Controller.extend({
dom: service('dom'),
builder: service('form'),
init: function() {
this._super(...arguments);
this.form = get(this, 'builder').form('intention');
},
setProperties: function(model) {
this.changeset = new Changeset(model.item, lookupValidator(validations), validations);
const sourceName = get(model.item, 'SourceName');
const destinationName = get(model.item, 'DestinationName');
let source = model.items.findBy('Name', sourceName);
@ -23,7 +25,7 @@ export default Controller.extend({
this._super({
...model,
...{
item: this.changeset,
item: this.form.setData(model.item).getData(),
SourceName: source,
DestinationName: destination,
},
@ -36,37 +38,44 @@ export default Controller.extend({
isUnique: function(term) {
return !get(this, 'items').findBy('Name', term);
},
change: function(e, value, _target) {
// normalize back to standard event
const target = e.target || { ..._target, ...{ name: e, value: value } };
let name, selected;
name = selected = target.value;
// TODO:
// linter needs this here?
change: function(e, value, item) {
const event = get(this, 'dom').normalizeEvent(e, value);
const form = get(this, 'form');
const target = event.target;
let name;
let selected;
let match;
switch (target.name) {
case 'Description':
case 'Action':
set(this.changeset, target.name, target.value);
break;
case 'SourceName':
case 'DestinationName':
name = selected = target.value;
// Names can be selected Service EmberObjects or typed in strings
// if its not a string, use the `Name` from the Service EmberObject
if (typeof name !== 'string') {
name = get(target.value, 'Name');
}
// linter doesn't like const here
// see if the name is already in the list
match = get(this, 'items').filterBy('Name', name);
if (match.length === 0) {
// if its not make a new 'fake' Service that doesn't exist yet
// and add it to the possible services to make an intention between
selected = { Name: name };
// linter doesn't mind const here?
const items = [selected].concat(this.items.toArray());
set(this, 'items', items);
}
set(this.changeset, target.name, name);
// mutate the value with the string name
// which will be handled by the form
target.value = name;
// these are 'non-form' variables so not on `item`
// these variables also exist in the template so we know
// the current selection
// basically the difference between
// `item.DestinationName` and just `DestinationName`
set(this, target.name, selected);
break;
}
this.changeset.validate();
form.handleEvent(event);
},
},
});

View file

@ -2,41 +2,56 @@ import Controller from '@ember/controller';
import { get, set } from '@ember/object';
import { inject as service } from '@ember/service';
import Changeset from 'ember-changeset';
import validations from 'consul-ui/validations/kv';
import lookupValidator from 'ember-changeset-validations';
export default Controller.extend({
json: true,
dom: service('dom'),
builder: service('form'),
encoder: service('btoa'),
json: true,
init: function() {
this._super(...arguments);
this.form = get(this, 'builder').form('kv');
},
setProperties: function(model) {
// essentially this replaces the data with changesets
this._super(
Object.keys(model).reduce((prev, key, i) => {
switch (key) {
case 'item':
prev[key] = this.form.setData(prev[key]).getData();
break;
}
return prev;
}, model)
);
},
actions: {
change: function(e, value, item) {
const event = get(this, 'dom').normalizeEvent(e, value);
const form = get(this, 'form');
try {
form.handleEvent(event);
} catch (err) {
const target = event.target;
let parent;
switch (target.name) {
case 'value':
set(this.item, 'Value', get(this, 'encoder').execute(target.value));
break;
case 'additional':
parent = get(this, 'parent.Key');
set(this.item, 'Key', `${parent !== '/' ? parent : ''}${target.value}`);
break;
case 'json':
// TODO: Potentially save whether json has been clicked to the model,
// setting set(this, 'json', true) here will force the form to always default to code=on
// even if the user has selected code=off on another KV
// ideally we would save the value per KV, but I'd like to not do that on the model
// a set(this, 'json', valueFromSomeStorageJustForThisKV) would be added here
this.changeset = new Changeset(model.item, lookupValidator(validations), validations);
this._super({
...model,
...{
item: this.changeset,
},
});
},
actions: {
change: function(e) {
const target = e.target || { name: 'value', value: e };
var parent;
switch (target.name) {
case 'additional':
parent = get(this, 'parent.Key');
set(this.changeset, 'Key', `${parent !== '/' ? parent : ''}${target.value}`);
break;
case 'json':
set(this, 'json', !get(this, 'json'));
break;
case 'value':
set(this, 'item.Value', get(this, 'encoder').execute(target.value));
break;
default:
throw err;
}
}
},
},

6
ui-v2/app/forms/acl.js Normal file
View file

@ -0,0 +1,6 @@
import validations from 'consul-ui/validations/acl';
import builderFactory from 'consul-ui/utils/form/builder';
const builder = builderFactory();
export default function(name = '', v = validations, form = builder) {
return form(name, {}).setValidators(v);
}

View file

@ -0,0 +1,6 @@
import validations from 'consul-ui/validations/intention';
import builderFactory from 'consul-ui/utils/form/builder';
const builder = builderFactory();
export default function(name = '', v = validations, form = builder) {
return form(name, {}).setValidators(v);
}

6
ui-v2/app/forms/kv.js Normal file
View file

@ -0,0 +1,6 @@
import validations from 'consul-ui/validations/kv';
import builderFactory from 'consul-ui/utils/form/builder';
const builder = builderFactory();
export default function(name = '', v = validations, form = builder) {
return form(name, {}).setValidators(v);
}

View file

@ -1,6 +1,6 @@
import builderFactory from 'consul-ui/utils/form/builder';
import validations from 'consul-ui/validations/token';
import policy from 'consul-ui/forms/policy';
import builderFactory from 'consul-ui/utils/form/builder';
const builder = builderFactory();
export default function(name = '', v = validations, form = builder) {
return form(name, {})

View file

@ -1,11 +1,17 @@
import kv from 'consul-ui/forms/kv';
import acl from 'consul-ui/forms/acl';
import token from 'consul-ui/forms/token';
import policy from 'consul-ui/forms/policy';
import intention from 'consul-ui/forms/intention';
export function initialize(application) {
// Service-less injection using private properties at a per-project level
const FormBuilder = application.resolveRegistration('service:form');
const forms = {
kv: kv(),
acl: acl(),
token: token(),
policy: policy(),
intention: intention(),
};
FormBuilder.reopen({
form: function(name) {

View file

@ -14,7 +14,7 @@
</div>
<label class="type-text">
<span>Policy <a href="{{env 'CONSUL_DOCUMENTATION_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a></span>
{{code-editor class=(if item.error.Rules 'error') name='Rules' value=item.Rules syntax="hcl" onkeyup=(action 'change')}}
{{code-editor class=(if item.error.Rules 'error') name='Rules' value=item.Rules syntax="hcl" onkeyup=(action 'change' 'Rules')}}
</label>
{{#if create }}
<label class="type-text">

View file

@ -18,7 +18,7 @@
<label class="type-text{{if item.error.Value ' has-error'}}">
<span>Value</span>
{{#if json}}
{{ code-editor value=(atob item.Value) onkeyup=(action 'change') }}
{{code-editor value=(atob item.Value) onkeyup=(action 'change' 'value')}}
{{else}}
<textarea autofocus={{not create}} name="value" oninput={{action 'change'}}>{{atob item.Value}}</textarea>
{{/if}}

View file

@ -2,7 +2,7 @@ import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:dc/acls/create', 'Unit | Controller | dc/acls/create', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
needs: ['service:dom', 'service:form'],
});
// Replace this with your real tests.

View file

@ -2,7 +2,7 @@ import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:dc/acls/edit', 'Unit | Controller | dc/acls/edit', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
needs: ['service:dom', 'service:form'],
});
// Replace this with your real tests.

View file

@ -2,7 +2,7 @@ import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:dc/intentions/create', 'Unit | Controller | dc/intentions/create', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
needs: ['service:dom', 'service:form'],
});
// Replace this with your real tests.

View file

@ -2,7 +2,7 @@ import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:dc/intentions/edit', 'Unit | Controller | dc/intentions/edit', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
needs: ['service:dom', 'service:form'],
});
// Replace this with your real tests.

View file

@ -2,7 +2,7 @@ import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:dc/kv/create', 'Unit | Controller | dc/kv/create', {
// Specify the other units that are required for this test.
needs: ['service:btoa'],
needs: ['service:btoa', 'service:dom', 'service:form'],
});
// Replace this with your real tests.

View file

@ -2,7 +2,7 @@ import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:dc/kv/edit', 'Unit | Controller | dc/kv/edit', {
// Specify the other units that are required for this test.
needs: ['service:btoa'],
needs: ['service:btoa', 'service:dom', 'service:form'],
});
// Replace this with your real tests.

View file

@ -2,7 +2,7 @@ import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:dc/kv/root-create', 'Unit | Controller | dc/kv/root-create', {
// Specify the other units that are required for this test.
needs: ['service:btoa'],
needs: ['service:btoa', 'service:dom', 'service:form'],
});
// Replace this with your real tests.