Skip to content

Commit

Permalink
This closes apache#72
Browse files Browse the repository at this point in the history
  • Loading branch information
ahgittin committed Sep 26, 2018
2 parents de857cf + 4310fbd commit a32e8f1
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 35 deletions.
Expand Up @@ -236,8 +236,8 @@ function BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService)

promise.then((data)=> {
deferred.resolve(populateEntityFromApiSuccess(entity, data));
}).catch(function () {
deferred.resolve(populateEntityFromApiError(entity));
}).catch(function (error) {
deferred.resolve(populateEntityFromApiError(entity, error));
});
} else if (entity.parent) {
entity.clearIssues({group: 'type'}).addIssue(Issue.builder().group('type').message('Entity needs a type').level(ISSUE_LEVEL.WARN).build());
Expand Down Expand Up @@ -275,20 +275,54 @@ function BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService)
return $q((resolve) => {
if (entity.miscData.has('config')) {
entity.miscData.get('config')
.filter(config => config.constraints && Object.keys(config.constraints).length > 0)
.filter(config => config.constraints && config.constraints.length > 0)
.forEach(config => {
for (let [key, constraint] of Object.entries(config.constraints) ) {
for (let constraintO of config.constraints) {
let message = null;
let key = null, args = null;
if (constraintO instanceof String) {
key = constraintO;
} else if (Object.keys(constraintO).length==1) {
key = Object.keys(constraintO)[0];
args = constraintO[key];
} else {
$log.warn("Unknown constraint object", constraintO);
key = constraintO;
}
let val = (k) => entity.config.get(k || config.name);
let isSet = (k) => entity.config.has(k || config.name) && angular.isDefined(val(k));
let hasDefault = () => angular.isDefined(config.defaultValue);
switch (key) {
case 'Predicates.notNull()':
case 'required':
if (!angular.isDefined(config.defaultValue) && (!entity.config.has(config.name) || !angular.isDefined(entity.config.get(config.name)))) {
if (!isSet() && !hasDefault() && val()!='') {
// "required" also means that it must not be the empty string
message = `<samp>${config.name}</samp> is required`;
}
break;
case 'regex':
if (!entity.config.has(config.name) || !angular.isDefined(entity.config.get(config.name)) || !(new RegExp(constraint).test(entity.config.get(config.name)))) {
message = `<samp>${config.name}</samp> does not match the required format: <samp>${config.constraints.regex}</samp>`;
if (isSet() && !(new RegExp(args).test(val))) {
message = `<samp>${config.name}</samp> does not match the required format: <samp>${args}</samp>`;
}
break;
case 'forbiddenIf':
if (isSet() && isSet(args)) {
message = `<samp>${config.name}</samp> cannot be set when <samp>${args}</samp> is set`;
}
break;
case 'forbiddenUnless':
if (isSet() && !isSet(args)) {
message = `<samp>${config.name}</samp> cannot be set unless <samp>${args}</samp> is set`;
}
break;
case 'requiredIf':
if (!isSet() && isSet(args)) {
message = `<samp>${config.name}</samp> is required when <samp>${args}</samp> is set`;
}
break;
case 'requiredUnless':
if (!isSet() && !isSet(args)) {
message = `<samp>${config.name}</samp> is required when <samp>${args}</samp> is not set`;
}
break;
}
Expand Down Expand Up @@ -321,8 +355,8 @@ function BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService)

paletteApi.getType(policy.type, policy.version).then((data)=> {
deferred.resolve(populateEntityFromApiSuccess(policy, data));
}).catch(function () {
deferred.resolve(populateEntityFromApiError(policy));
}).catch(function (error) {
deferred.resolve(populateEntityFromApiError(policy, error));
}).finally(()=> {
policy.miscData.set('loading', false);
});
Expand All @@ -340,8 +374,8 @@ function BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService)

paletteApi.getType(enricher.type, enricher.version).then((data)=> {
deferred.resolve(populateEntityFromApiSuccess(enricher, data));
}).catch(function () {
deferred.resolve(populateEntityFromApiError(enricher));
}).catch(function (error) {
deferred.resolve(populateEntityFromApiError(enricher, error));
}).finally(()=> {
enricher.miscData.set('loading', false);
});
Expand Down Expand Up @@ -482,21 +516,7 @@ function BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService)
version: data.containingBundle.split(':')[1]
});
entity.miscData.set('typeName', data.displayName || data.symbolicName);
entity.miscData.set('config', (data.config || []).map(config => {
if (config.constraints) {
config.constraints = config.constraints.reduce((map, constraint) => {
if (constraint.startsWith('matchesRegex')) {
map.regex = constraint.replace(/matchesRegex\(([^)]*)\)/, '$1');
} else {
// The constraint "required" falls back into this case. Good enough for now as we only support
// 2 types of constraints.
map[constraint] = true;
}
return map;
}, {});
}
return config;
}));
entity.miscData.set('config', data.config || []);
entity.miscData.set('sensors', data.sensors || []);
entity.miscData.set('traits', data.supertypes || []);
entity.miscData.set('tags', data.tags || []);
Expand All @@ -520,7 +540,8 @@ function BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService)
return dst;
}

function populateEntityFromApiError(entity) {
function populateEntityFromApiError(entity, error) {
$log.warn("Error loading/populating type, data will be incomplete.", entity, error);
entity.clearIssues({group: 'type'});
entity.addIssue(Issue.builder().group('type').message($sce.trustAsHtml(`Type <samp>${entity.type + (entity.hasVersion ? ':' + entity.version : '')}</samp> does not exist`)).build());
entity.miscData.set('typeName', entity.type || '');
Expand Down
Expand Up @@ -50,15 +50,16 @@ export const CONFIG_FILTERS = [
{
id: 'required',
label: 'Required',
filter: (item)=> {
return item.constraints && item.constraints.required;
filter: (item, model)=> {
return (item.constraints && item.constraints.required) ||
(model && model.issues && model.issues.some((issue)=>(issue.group === 'config' && issue.ref === item.name)) );
}
},
{
id: 'inuse',
label: 'In Use',
filter: (item, currentConfig)=> {
return currentConfig.has(item.name);
filter: (item, model)=> {
return model && model.config && model.config.has(item.name);
}
},
{
Expand Down Expand Up @@ -601,7 +602,7 @@ export function specEditorDirective($rootScope, $templateCache, $injector, $sani
if (!angular.isArray(scope.model.miscData.get('config'))) {
return [];
}
let filteredConfig = $filter('specEditorConfig')(scope.model.miscData.get('config'), scope.state.config.filter.values, scope.model.config);
let filteredConfig = $filter('specEditorConfig')(scope.model.miscData.get('config'), scope.state.config.filter.values, scope.model);
return scope.model.miscData.get('config').map((config)=> {
config.isHidden = scope.model.miscData.get('config').indexOf(config) > -1 ? filteredConfig.indexOf(config) === -1 : false;
return config;
Expand Down Expand Up @@ -827,7 +828,7 @@ export function specEditorDirective($rootScope, $templateCache, $injector, $sani
}

export function specEditorConfigFilter() {
return function (input, filtersMapById, currentConfig) {
return function (input, filtersMapById, model) {
let filters = [];
Object.keys(filtersMapById).forEach( (k) => { if (filtersMapById[k]) filters.push(k); } );

Expand All @@ -838,7 +839,7 @@ export function specEditorConfigFilter() {
return input;
}
return input.filter((item)=> {
return filters.some(filterId => CONFIG_FILTERS.find(filter => filter.id === filterId).filter(item, currentConfig));
return filters.some(filterId => CONFIG_FILTERS.find(filter => filter.id === filterId).filter(item, model));
});
}
}
Expand Down
Expand Up @@ -126,7 +126,7 @@ <h4>No matching configuration</h4>
</div>

<form name="formSpecConfig" novalidate class="lightweight">
<div ng-repeat="item in (filteredItems = (model.miscData.get('config') | specEditorConfig:state.config.filter.values:model.config | filter:{name:state.config.search} | orderBy:+priority)) track by item.name ">
<div ng-repeat="item in (filteredItems = (model.miscData.get('config') | specEditorConfig:state.config.filter.values:model | filter:{name:state.config.search} | orderBy:+priority)) track by item.name ">
<div class="form-group" ng-class="{'has-error': (model.issues | filter:{ref: item.name}:true).length > 0, 'used': config[item.name] !== undefined}"
ng-switch="getConfigWidgetMode(item)"
tabindex="1"
Expand Down

0 comments on commit a32e8f1

Please sign in to comment.