More metadata editor, tab/untab with selection

This commit is contained in:
Vincent Fiduccia 2017-10-02 18:25:04 -07:00
parent 46dd00a382
commit a535c3ba3d
No known key found for this signature in database
GPG Key ID: 2B29AD6BB2BB2582
5 changed files with 114 additions and 55 deletions

View File

@ -96,18 +96,20 @@ export default Ember.Component.extend(NewOrEdit, {
this.set('launchConfig.secrets', []); this.set('launchConfig.secrets', []);
} }
if ( !this.get('launchConfig.metadata') ) {
this.set('launchConfig.metadata', {});
};
if ( this.get('isService') && !this.get('isSidekick') ) { if ( this.get('isService') && !this.get('isSidekick') ) {
this.setProperties({ this.setProperties({
name: this.get('service.name'), name: this.get('service.name'),
description: this.get('service.description'), description: this.get('service.description'),
scale: this.get('service.scale'), scale: this.get('service.scale'),
metadata: this.get('service.metadata') || {},
}); });
} else { } else {
this.setProperties({ this.setProperties({
name: this.get('launchConfig.name'), name: this.get('launchConfig.name'),
description: this.get('launchConfig.description'), description: this.get('launchConfig.description'),
metadata: {},
}); });
} }
@ -264,7 +266,6 @@ export default Ember.Component.extend(NewOrEdit, {
pr = this.get('service').clone(); pr = this.get('service').clone();
nameResource = pr; nameResource = pr;
pr.set('launchConfig', lc); pr.set('launchConfig', lc);
pr.set('metadata', this.get('metadata'))
pr.set('scale', this.get('scale')); pr.set('scale', this.get('scale'));
} else { } else {
// Convert the launch config to a container // Convert the launch config to a container

View File

@ -152,16 +152,16 @@
expandFn=expandFn expandFn=expandFn
}} }}
{{form-metadata
classNames="accordion-wrapper"
instance=launchConfig
errors=metadataErrors
expandAll=al.expandAll
expandFn=expandFn
}}
{{#if isService}} {{#if isService}}
{{#unless isSidekick}} {{#unless isSidekick}}
{{form-metadata
classNames="accordion-wrapper"
instance=metadata
errors=metadataErrors
expandAll=al.expandAll
expandFn=expandFn
}}
{{container/form-service-links {{container/form-service-links
service=service service=service
expandAll=al.expandAll expandAll=al.expandAll

View File

@ -4,13 +4,12 @@ import { STATUS, STATUS_INTL_KEY, classForStatus } from 'ui/components/accordion
export default Ember.Component.extend({ export default Ember.Component.extend({
intl: Ember.inject.service(), intl: Ember.inject.service(),
classNames: ['accordion-wrapper'],
detailKey: 'formMetadata.detail',
instance: null, instance: null,
detailKey: 'formMetadata.detail',
errors: null, errors: null,
invalid: false, valid: true,
classNames: ['accordion-wrapper'],
didReceiveAttrs() { didReceiveAttrs() {
if (!this.get('expandFn')) { if (!this.get('expandFn')) {
@ -22,26 +21,28 @@ export default Ember.Component.extend({
validate: function () { validate: function () {
let intl = this.get('intl'); let intl = this.get('intl');
if (this.get('invalid')) { if ( this.get('valid') ) {
this.set('errors', [intl.t('formMetadata.errors.invalidJSON')]) if ( ['object', 'null'].indexOf(Ember.typeOf(this.get('instance.metadata'))) === -1 ) {
} else if (['object', 'null'].indexOf(Ember.typeOf(this.get('instance'))) === -1) { this.set('errors', [intl.t('formMetadata.errors.topLevelValueInvalid')]);
this.set('errors', [intl.t('formMetadata.errors.topLevelValueInvalid')]); } else {
this.set('errors', []);
}
} else { } else {
this.set('errors', []); this.set('errors', [intl.t('formMetadata.errors.invalidJSON')]);
} }
}.observes('invalid', 'instance'), }.observes('valid', 'instance.metadata'),
statusClass: null, statusClass: null,
status: function () { status: function () {
let k; let k;
if (this.get('invalid') || ['object', 'null'].indexOf(Ember.typeOf(this.get('instance'))) === -1) { if (this.get('errors.length') ) {
k = STATUS.ERROR; k = STATUS.ERROR;
} else if (!Ember.isNone(this.get('instance')) && Object.keys(this.get('instance')).length > 0) { } else if (!Ember.isNone(this.get('instance.metadata')) && Object.keys(this.get('instance.metadata')).length > 0) {
k = STATUS.CONFIGURED; k = STATUS.CONFIGURED;
} else { } else {
k = STATUS.NOTCONFIGURED; k = STATUS.NOTCONFIGURED;
} }
this.set('statusClass', classForStatus(k)); this.set('statusClass', classForStatus(k));
return this.get('intl').t(`${STATUS_INTL_KEY}.${k}`); return this.get('intl').t(`${STATUS_INTL_KEY}.${k}`);
}.property('invalid'), }.property('errors.length'),
}); });

View File

@ -6,5 +6,5 @@
expandAll=expandAll expandAll=expandAll
expand=(action expandFn) expand=(action expandFn)
}} }}
{{json-editor json=instance isInvalid=invalid}} {{json-editor json=instance.metadata isValid=valid}}
{{/accordion-list-item}} {{/accordion-list-item}}

View File

@ -2,51 +2,108 @@ import Ember from 'ember';
import sanitize from 'json-sanitizer'; import sanitize from 'json-sanitizer';
import C from 'ui/utils/constants'; import C from 'ui/utils/constants';
const TAB_SIZE = 2;
const TAB_STR = (new Array(TAB_SIZE+1)).join(' ');
export default Ember.Component.extend({ export default Ember.Component.extend({
json: {}, jsonString: null,
isInvalid: false,
tagName: 'div', tagName: 'div',
classNames: ['jsoneditor-component'], classNames: ['jsoneditor-component'],
jsonString: function () { json: {},
return JSON.stringify(this.get('json'), undefined, 4); isValid: true,
}.property('json'),
onChange: function () { init() {
try { this._super();
const json = this.parseJSON(this.jsonString) this.focusOut();
this.set('json', json);
this.set('isInvalid', false)
} catch (err) {
this.set('isInvalid', true)
}
}.observes('jsonString'),
parseJSON: function (jsonString) {
try {
return JSON.parse(jsonString);
} catch (err) {
return JSON.parse(sanitize(jsonString));
}
}, },
focusOut() { focusOut() {
if (!this.get('isInvalid')) { if ( this.get('isValid') ) {
this.set('jsonString', JSON.stringify(this.get('json'), undefined, 4)); this.set('jsonString', JSON.stringify(this.get('json'), undefined, TAB_SIZE));
} }
}, },
keyDown: function (event) { keyDown(event) {
const keyCode = event.which; const keyCode = event.which;
if (keyCode === C.KEY.TAB) { if (keyCode === C.KEY.TAB) {
event.preventDefault(); event.preventDefault();
const el = $(this).get(0).childViews.get(0).element; const el = $(this).get(0).childViews.get(0).element;
const start = el.selectionStart; const val = $(el).val();
const end = el.selectionEnd;
$(el).val($(el).val().substring(0, start) + " " + $(el).val().substring(end)); let start = el.selectionStart;
el.selectionStart = start + 4; let end = el.selectionEnd;
el.selectionEnd = start + 4; const origStart = start;
const origEnd = end;
// Move start to the beginning of the line
while ( start > 0 && val.charAt(start-1) !== '\n' ) {
start--;
}
// And end to the end of the line
while ( end < val.length && val.charAt(end) !== '\n') {
end++;
}
let lines = val.substring(start,end).split(/\n/);
let sub;
let direction;
if ( event.shiftKey ) {
const re = new RegExp("^(\\s{"+ TAB_SIZE + "}|\\t)");
let found = false;
sub = lines.map((x) => {
let out = x.replace(re,'');
if ( out !== x ) {
found = true;
}
return out;
});
if ( found ) {
direction = -1;
} else {
// If no lines moved, this will prevent the cursor from moving back
direction = 0;
}
} else {
sub = lines.map(x => TAB_STR+x);
direction = 1;
}
let replaceStr = sub.join("\n");
$(el).val(val.substring(0, start) + replaceStr + val.substring(end));
if ( origStart === origEnd ) {
el.selectionStart = el.selectionEnd = origStart + direction*TAB_SIZE*sub.length;
} else {
el.selectionStart = start;
el.selectionEnd = start + replaceStr.length;
}
}
},
onChange: function() {
const [json, isValid] = this.parse(this.get('jsonString'));
this.setProperties({
json,
isValid,
});
}.observes('jsonString'),
parse(jsonString) {
try {
const json = JSON.parse(jsonString);
return [json,true];
} catch (err) {
try {
const json = JSON.parse(sanitize(jsonString));
return [json,true];
} catch (err) {
return [null,false];
}
} }
}, },
}); });