Merge pull request #124 from ahgittin/fix-dsl-literal
DSL Viewer ignored literals; this fixes that and tidies the code a bit
diff --git a/ui-modules/blueprint-composer/app/components/custom-config-widget/suggestion-dropdown.js b/ui-modules/blueprint-composer/app/components/custom-config-widget/suggestion-dropdown.js
index d58ec88..0899c0a 100644
--- a/ui-modules/blueprint-composer/app/components/custom-config-widget/suggestion-dropdown.js
+++ b/ui-modules/blueprint-composer/app/components/custom-config-widget/suggestion-dropdown.js
@@ -46,21 +46,28 @@
};
function link(scope, element, attrs, specEditor) {
- scope.specEditor = specEditor;
- scope.defined = specEditor.defined;
- scope.getSuggestions = () => {
- var result = [];
- if (scope.params['suggestion-values']) {
- scope.params['suggestion-values'].forEach( (v) => {
- if (v["value"]) {
- result.push(v);
- } else {
- result.push({value: v});
- }
- });
- return result;
+ try {
+ scope.specEditor = specEditor;
+ scope.defined = specEditor.defined;
+ scope.getSuggestions = () => {
+ var result = [];
+ if (scope.params['suggestion-values']) {
+ scope.params['suggestion-values'].forEach( (v) => {
+ if (v["value"]) {
+ result.push(v);
+ } else {
+ result.push({value: v});
+ }
+ });
+ return result;
+ }
+ };
+ } catch (e) {
+ if ($scope.params) {
+ $scope.params.error = e;
}
- };
+ throw e;
+ }
}
}
diff --git a/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js b/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
index 38604a3..7808a98 100644
--- a/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
+++ b/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
@@ -265,15 +265,28 @@
return deferred.promise;
}
+ function locationType(location) {
+ if (!location || typeof location === 'string') return location;
+ if (typeof location === 'object' && Object.keys(location).length==1) return Object.keys(location)[0];
+ return null;
+ }
+
function refreshLocationMetadata(entity) {
let deferred = $q.defer();
if (entity.hasLocation()) {
- paletteApi.getLocation(entity.location).then((location)=> {
- deferred.resolve(populateLocationFromApiSuccess(entity, location.catalog || location));
- }).catch(function () {
- deferred.resolve(populateLocationFromApiError(entity));
- });
+ let type = locationType(entity.location);
+ if (type.startsWith("jclouds:")) {
+ // types eg jclouds:aws-ec2 are low-level, not in the catalog
+ deferred.resolve(populateLocationFromApiSuccess(entity, { yamlHere: entity.location }));
+ } else {
+ paletteApi.getLocation(locationType(entity.location)).then((location)=> {
+ let loc = Object.assign({}, location.catalog || location, { yamlHere: entity.location });
+ deferred.resolve(populateLocationFromApiSuccess(entity, loc));
+ }).catch(function () {
+ deferred.resolve(populateLocationFromApiError(entity));
+ });
+ }
} else {
deferred.resolve(entity);
}
@@ -601,18 +614,30 @@
return entity;
}
- function populateLocationFromApiSuccess(entity, data) {
+ function populateLocationFromApiCommon(entity, data) {
entity.clearIssues({group: 'location'});
- entity.location = data.symbolicName;
- entity.miscData.set('locationName', data.name);
- entity.miscData.set('locationIcon', data.iconUrl || iconGenerator(data.symbolicName));
+ entity.location = data.yamlHere || data.symbolicName;
+
+ let name = data.name || data.displayName;
+ if (!name && data.yamlHere) {
+ name = typeof data.yamlHere === 'object' ? Object.keys(data.yamlHere)[0] : data.yamlHere;
+ }
+ if (!name) name = data.symbolicName;
+ entity.miscData.set('locationName', name);
+
+ // use icon on item, but if none then generate using *yaml* to distinguish when someone has changed it
+ // (especially for things like jclouds:aws-ec2 -- the config is more interesting than the type name)
+ entity.miscData.set('locationIcon', data==null ? null : data.iconUrl || iconGenerator(data.yamlHere ? JSON.stringify(data.yamlHere) : data.symbolicName));
return entity;
}
+
+ function populateLocationFromApiSuccess(entity, data) {
+ populateLocationFromApiCommon(entity, data);
+ }
function populateLocationFromApiError(entity) {
- entity.clearIssues({group: 'location'});
+ populateLocationFromApiCommon(entity, { yamlHere: entity.location });
entity.addIssue(Issue.builder().level(ISSUE_LEVEL.WARN).group('location').message($sce.trustAsHtml(`Location <samp>${!(entity.location instanceof String) ? JSON.stringify(entity.location) : entity.location}</samp> does not exist in your local catalog. Deployment might fail.`)).build());
- entity.miscData.set('locationName', entity.location);
entity.miscData.set('locationIcon', typeNotFoundIcon);
return entity;
}
diff --git a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.directive.js b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.directive.js
index 53be4f2..95c59e4 100644
--- a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.directive.js
+++ b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.directive.js
@@ -254,6 +254,8 @@
}
scope.nonempty = (o) => o && Object.keys(o).length;
scope.defined = specEditor.defined = (o) => (typeof o !== 'undefined');
+ specEditor.isInstance = (x, type) => (typeof x === type);
+
specEditor.advanceOutToFormGroupInPanel = (element, event) => {
focusIfPossible(event, findAncestor(element, "form-group", "panel-body")) || element[0].blur();
};
@@ -571,16 +573,35 @@
/** returns 'enabled' or 'disabled' if a widget is defined, or null if no special widget is defined */
specEditor.getCustomConfigWidgetMode = (item) => {
var widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
- if (!widgetMetadata || widgetMetadata["error"]) return null;
+ if (!widgetMetadata) return null;
+ if (widgetMetadata["error"]) {
+ return "disabled";
+ }
return widgetMetadata["enabled"] ? 'enabled' : 'disabled';
};
+ specEditor.customConfigWidgetError = (item) => {
+ var widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
+ if (!widgetMetadata || !widgetMetadata["error"]) return null;
+ if (widgetMetadata.manualToggleAfterError && widgetMetadata.enabled) {
+ // show the error if manually enabled
+ return widgetMetadata["error"];
+ }
+ return null;
+ };
specEditor.toggleCustomConfigWidgetMode = (item, newval) => {
var widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
if (!widgetMetadata) {
$log.error('Custom widget mode should not be toggled when not available: '+item.name);
return null;
}
- if (!specEditor.defined(newval)) newval = !widgetMetadata.enabled;
+ if (!specEditor.defined(newval)) {
+ if (widgetMetadata["error"] && !widgetMetadata.manualToggleAfterError) {
+ widgetMetadata.manualToggleAfterError = true;
+ newval = true;
+ } else {
+ newval = !widgetMetadata.enabled;
+ }
+ }
widgetMetadata.enabled = newval;
}
specEditor.getCustomConfigWidgetModeTitle = (item) => {
@@ -715,7 +736,7 @@
return scope.config[key];
}
} catch (ignoredError) {
- console.log("Couldn't handle entered JSON", scope.config[key], ignoredError);
+ $log.debug("Couldn't handle entered JSON", scope.config[key], ignoredError);
}
}
// otherwise pretty print it, so they get decent multiline on first load and
diff --git a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.less b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.less
index 591e046..15dd9d3 100644
--- a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.less
+++ b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.less
@@ -22,9 +22,6 @@
@hide-info-button-when-not-hovered: false;
@hide-unset-undefault-values: true;
-@label-gray: darken(@gray-light, 10%);
-@gray-lightest: #f8f8f9;
-
spec-editor {
display: block;
margin-top: 15px;
diff --git a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.template.html b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.template.html
index 31af6f8..fe00172 100644
--- a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.template.html
+++ b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.template.html
@@ -127,7 +127,7 @@
<form name="formSpecConfig" novalidate class="lightweight">
<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}"
+ <div class="form-group" ng-class="{'has-error': ((model.issues | filter:{ref: item.name}:true).length > 0) || (specEditor.customConfigWidgetError(item)), 'used': config[item.name] !== undefined}"
ng-switch="getConfigWidgetMode(item)"
tabindex="1"
auto-focus="state.config.focus === item.name"
@@ -332,6 +332,10 @@
</div>
<small ng-repeat="issue in model.issues | filter:{ref: item.name}:true" class="help-block issue" ng-bind-html="issue.message"></small>
+ <small ng-if="specEditor.customConfigWidgetError(item)" class="help-block issue">
+ Custom widget unavailable:
+ {{ specEditor.customConfigWidgetError(item) }}
+ </small>
</div>
</div>
@@ -362,7 +366,12 @@
<p ng-repeat="issue in state.issues | filter:{group:'location'}" class="alert alert-{{issue.severity}}">
<em ng-bind-html="issue.message"></em>
</p>
- <p>Will be deployed to: <strong>{{model.miscData.get('locationName')}}</strong></p>
+ <p>
+ Targeted at:
+ <strong ng-if="specEditor.isInstance(model.location, 'string')">{{ model.miscData.get('locationName') }}</strong>
+ <pre ng-if="!specEditor.isInstance(model.location, 'string')">{{ model.location | json }}</pre>
+ </p>
+ <br/>
<a class="btn btn-default" ui-sref="main.graphical.edit.add({entityId: model._id, family: 'location'})">Change location</a>
<button class="btn btn-danger btn-link" ng-click="model.clearIssues({group: 'location'}).removeLocation()">Remove</button>
</div>
diff --git a/ui-modules/blueprint-composer/app/components/util/d3-blueprint.js b/ui-modules/blueprint-composer/app/components/util/d3-blueprint.js
index b25bc04..b199ab0 100755
--- a/ui-modules/blueprint-composer/app/components/util/d3-blueprint.js
+++ b/ui-modules/blueprint-composer/app/components/util/d3-blueprint.js
@@ -173,7 +173,8 @@
relationships: [],
};
- let zoom = d3.zoom().scaleExtent([0.1, 1]).on('zoom', onSvgZoom);
+ let viewportWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
+ let zoom = d3.zoom().scaleExtent([0.1, Math.max(1, 1 + Math.log(viewportWidth/1024))]).on('zoom', onSvgZoom);
_svg
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr('viewBox', () => {
@@ -617,11 +618,13 @@
.duration(_configHolder.transition)
.attr('opacity', (d)=>(d.data.hasLocation() ? 1 : 0));
appendElements(location, _configHolder.nodes.location);
+
nodeData.select('g.node-location image')
.transition()
.duration(_configHolder.transition)
- .attr('opacity', (d)=>(d.data.miscData.get('locationIcon') ? 1 : 0))
- .attr('xlink:href', (d)=>(d.data.miscData.get('locationIcon')));
+ .attr('opacity', (d)=>(d.data.miscData.get('locationIcon') ? 1 : 0));
+ nodeData.select('g.node-location image')
+ .attr('xlink:href', (d)=>d.data.miscData.get('locationIcon'));
// Draw important adjuncts (i.e policies/enrichers)
// -----------------------------------------------------
diff --git a/ui-modules/blueprint-composer/app/components/util/model/entity.model.js b/ui-modules/blueprint-composer/app/components/util/model/entity.model.js
index 603eaa9..6f4ad40 100644
--- a/ui-modules/blueprint-composer/app/components/util/model/entity.model.js
+++ b/ui-modules/blueprint-composer/app/components/util/model/entity.model.js
@@ -272,6 +272,7 @@
*/
set location(location) {
LOCATIONS.set(this, location);
+ this.miscData.delete('locationRemoved');
this.touch();
}
@@ -281,6 +282,13 @@
*/
removeLocation() {
LOCATIONS.delete(this);
+ this.miscData.delete('locationName');
+ this.miscData.delete('locationIcon');
+
+ // this field provides a way for consumers to detect if the location was explicitly removed;
+ // this can be useful to prevent default locations from being applied
+ this.miscData.set('locationRemoved', true);
+
this.touch();
}
diff --git a/ui-modules/blueprint-composer/app/index.less b/ui-modules/blueprint-composer/app/index.less
index 86e52dc..e42474c 100644
--- a/ui-modules/blueprint-composer/app/index.less
+++ b/ui-modules/blueprint-composer/app/index.less
@@ -37,9 +37,6 @@
@import "components/dsl-editor/dsl-editor";
@import "components/dsl-viewer/dsl-viewer";
-@gray-lighter: #E1E5E7;
-@gray-light: #818899;
-
.make-icon(@size) {
width: auto;
height: auto;
diff --git a/ui-modules/location-manager/app/views/detail/detail.controller.js b/ui-modules/location-manager/app/views/detail/detail.controller.js
index 426c1a9..01c0818 100644
--- a/ui-modules/location-manager/app/views/detail/detail.controller.js
+++ b/ui-modules/location-manager/app/views/detail/detail.controller.js
@@ -86,7 +86,7 @@
$state.go('locations');
brSnackbar.create('Location "' + $filter('locationName')(vm.location) + '" deleted successfully');
}).catch(error => {
- brSnackbar.create('Could not delete this location: ' + error.message);
+ brSnackbar.create('Could not delete this location: ' + error.error.message);
});
};
vm.editLocation = function () {
diff --git a/ui-modules/location-manager/app/views/wizard/advanced/advanced.controller.js b/ui-modules/location-manager/app/views/wizard/advanced/advanced.controller.js
index 975d9c3..0107bc2 100644
--- a/ui-modules/location-manager/app/views/wizard/advanced/advanced.controller.js
+++ b/ui-modules/location-manager/app/views/wizard/advanced/advanced.controller.js
@@ -78,7 +78,7 @@
catalogApi.create(payload).then(data => {
$state.go('detail', {symbolicName: vm.id, version: vm.version});
}).catch(error => {
- brSnackbar.create('Could not save location: ' + error.data.message ? error.data.message : error.data);
+ brSnackbar.create('Could not save location: ' + error.error.message ? error.error.message : error.data);
});
};
diff --git a/ui-modules/location-manager/app/views/wizard/byon/byon.controller.js b/ui-modules/location-manager/app/views/wizard/byon/byon.controller.js
index c12c789..51ab1db 100644
--- a/ui-modules/location-manager/app/views/wizard/byon/byon.controller.js
+++ b/ui-modules/location-manager/app/views/wizard/byon/byon.controller.js
@@ -95,7 +95,7 @@
catalogApi.create(payload).then(data => {
$state.go('detail', {symbolicName: vm.id, version: vm.version});
}).catch(error => {
- brSnackbar.create('Could not save location: ' + error.data.message ? error.data.message : error.data);
+ brSnackbar.create('Could not save location: ' + error.error.message ? error.error.message : error.error);
});
};
diff --git a/ui-modules/location-manager/app/views/wizard/cloud/cloud.controller.js b/ui-modules/location-manager/app/views/wizard/cloud/cloud.controller.js
index 4e015c4..996a156 100644
--- a/ui-modules/location-manager/app/views/wizard/cloud/cloud.controller.js
+++ b/ui-modules/location-manager/app/views/wizard/cloud/cloud.controller.js
@@ -102,7 +102,7 @@
catalogApi.create(payload).then(data => {
$state.go('detail', {symbolicName: vm.id, version: vm.version});
}).catch(error => {
- brSnackbar.create('Could not save location: ' + error.data.message ? error.data.message : error.data);
+ brSnackbar.create('Could not save location: ' + error.error.message ? error.error.message : error.error);
});
};
diff --git a/ui-modules/utils/br-core/style/buttons.less b/ui-modules/utils/br-core/style/buttons.less
index e87dbc3..baefe44 100644
--- a/ui-modules/utils/br-core/style/buttons.less
+++ b/ui-modules/utils/br-core/style/buttons.less
@@ -23,6 +23,9 @@
.btn-accent {
.button-variant(@btn-accent-color; @btn-accent-bg; @btn-accent-border);
}
+.btn-light {
+ .button-variant(@gray-dark; @gray-lightest; @gray-lightest);
+}
.btn-outline {
&.btn-primary:not(:hover) {
@@ -49,4 +52,9 @@
background-color: transparent;
color: @brand-danger;
}
+
+ &.btn-light:not(:hover) {
+ background-color: transparent;
+ color: @gray-lightest;
+ }
}
diff --git a/ui-modules/utils/br-core/style/variables.less b/ui-modules/utils/br-core/style/variables.less
index efe673a..439ee28 100644
--- a/ui-modules/utils/br-core/style/variables.less
+++ b/ui-modules/utils/br-core/style/variables.less
@@ -21,18 +21,18 @@
@brand-accent: #bf3727;
-// Create path variables for fonts and images
-@br-core-path-font: '../fonts';
-@br-core-path-img: '../img';
-// Override the font-awesome path to use our custom one
-@fa-font-path: @br-core-path-font;
+// bootstrap colours at
+// https://github.com/twbs/bootstrap-sass/blob/master/assets/stylesheets/bootstrap/_variables.scss
+@gray-light: #818899; // override bootstrap default of #777
+@gray-lighter: #E1E5E7; // override bootstrap default of #eee
+@gray-lightest: #f8f8f9;
+@label-gray: darken(@gray-light, 10%); // between @gray and @gray-light
-@body-bg: hsl(223,30%,97%);
+@body-bg: hsl(223,30%,97%); // override bootstrap default, #333, same as @gray-dark, used for the button bar, body default bg colour from bootstrap scaffolding
+
@card-border-color: mix(black, @body-bg, 7%);
-@font-family-sans-serif: "myriad-pro-1", Helvetica, Arial, sans-serif;
-
/* Colors in pattern lab */
.brand-primary {
background-color: @brand-primary;
@@ -54,3 +54,13 @@
@state-accent-text: @accent-500;
@state-accent-bg: @accent-30;
@state-accent-border: darken(spin(@state-accent-bg, -10), 5%);
+
+
+// Create path variables for fonts and images
+
+@br-core-path-font: '../fonts';
+@br-core-path-img: '../img';
+// Override the font-awesome path to use our custom one
+@fa-font-path: @br-core-path-font;
+
+@font-family-sans-serif: "myriad-pro-1", Helvetica, Arial, sans-serif;
diff --git a/ui-modules/utils/table/index.js b/ui-modules/utils/table/index.js
index 9419b4d..bf12ef2 100644
--- a/ui-modules/utils/table/index.js
+++ b/ui-modules/utils/table/index.js
@@ -103,6 +103,7 @@
link: link,
controller: ['$templateCache', 'brUtilsGeneral', controller],
controllerAs: 'ctrl',
+ scope: true,
templateUrl: function(element, attrs) {
return attrs.templateUrl || TEMPLATE_CONTAINER_URL;
}
diff --git a/ui-modules/utils/yaml-editor/addon/schemas/blueprint.json b/ui-modules/utils/yaml-editor/addon/schemas/blueprint.json
index bbf118f..fcc8ebc 100644
--- a/ui-modules/utils/yaml-editor/addon/schemas/blueprint.json
+++ b/ui-modules/utils/yaml-editor/addon/schemas/blueprint.json
@@ -22,7 +22,6 @@
"title": "Blueprint",
"description": "A blueprint that is composed of one or more entities",
"type": "object",
- "required": [ "services" ],
"properties": {
"name": {
"title": "Blueprint name",