use markdown for description in blueprint composer
on type quickinfo from palette, and when type config editor shows, and on config in that editor
diff --git a/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.template.html b/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.template.html
index 3cf0cc9..a78c9fd 100644
--- a/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.template.html
+++ b/ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.template.html
@@ -162,7 +162,9 @@
<p><i class="mini-icon fa fa-fw fa-bookmark"></i> <samp class="type-symbolic-name">{{popover.symbolicName}}</samp></p>
<p ng-if="popover.version"><i class="mini-icon fa fa-fw fa-code-fork"></i> {{popover.version}}</p>
</div>
- <p class="quick-info-description" ng-if="popover.description">{{popover.description}}</p>
+ <p class="quick-info-description">
+ <md-first-line raw-data="::popover.description" raw-item="::popover"></md-first-line>
+ </p>
<p class="quick-info-description" ng-if="popover == freeFormTile">This is an ad hoc tile for an item entered by the user not known in the catalog.</p>
<div class="quick-info-metadata bundle">
<p ng-if="lastUsedText(popover)"><i class="mini-icon fa fa-clock-o"></i> {{ lastUsedText(popover) }}
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 a798d9c..19794ab 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
@@ -584,6 +584,9 @@
version: data.containingBundle.split(':')[1]
});
entity.miscData.set('typeName', data.displayName || data.symbolicName);
+ entity.miscData.set('displayName', data.displayName);
+ entity.miscData.set('symbolicName', data.symbolicName);
+ entity.miscData.set('description', data.description);
entity.miscData.set('config', data.config || []);
entity.miscData.set('parameters', data.parameters || []);
entity.miscData.set('sensors', data.sensors || []);
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 9106aa8..9da1581 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
@@ -35,7 +35,7 @@
const REPLACED_DSL_ENTITYSPEC = '___brooklyn:entitySpec';
angular.module(MODULE_NAME, [onEnter, autoGrow, blurOnEnter, brooklynDslEditor, brooklynDslViewer])
- .directive('specEditor', ['$rootScope', '$templateCache', '$injector', '$sanitize', '$filter', '$log', '$sce', '$timeout', '$document', '$state', '$compile', 'blueprintService', 'composerOverrides', specEditorDirective])
+ .directive('specEditor', ['$rootScope', '$templateCache', '$injector', '$sanitize', '$filter', '$log', '$sce', '$timeout', '$document', '$state', '$compile', 'blueprintService', 'composerOverrides', 'mdHelper', specEditorDirective])
.filter('specEditorConfig', specEditorConfigFilter)
.filter('specEditorType', specEditorTypeFilter)
.run(['$templateCache', templateCache]);
@@ -89,7 +89,7 @@
'string', 'boolean', 'integer', 'double', 'duration', ' port'
];
-export function specEditorDirective($rootScope, $templateCache, $injector, $sanitize, $filter, $log, $sce, $timeout, $document, $state, $compile, blueprintService, composerOverrides) {
+export function specEditorDirective($rootScope, $templateCache, $injector, $sanitize, $filter, $log, $sce, $timeout, $document, $state, $compile, blueprintService, composerOverrides, mdHelper) {
return {
restrict: 'E',
scope: {
@@ -118,6 +118,7 @@
scope.REPLACED_DSL_ENTITYSPEC = REPLACED_DSL_ENTITYSPEC;
scope.parameters = [];
scope.config = {};
+ specEditor.descriptionVisible = false;
specEditor.paramTypes = PARAM_TYPES;
specEditor.getParameter = getParameter;
@@ -214,6 +215,11 @@
// Model
scope.$watch('model', (newVal, oldVal) => {
if (newVal && !newVal.equals(oldVal)) {
+ scope.modelDescription = mdHelper.analyzeDescription({
+ description: newVal.miscData.get('description'),
+ symbolicName: newVal.miscData.get('symbolicName'),
+ displayName: newVal.miscData.get('displayName'),
+ });
loadLocalConfigFromModel();
loadLocalParametersFromModel();
}
@@ -470,16 +476,6 @@
return issues.some(issue => issue.level === ISSUE_LEVEL.ERROR) ? 'badge-danger' : 'badge-warning';
};
- specEditor.descriptionHtml = (text) => {
- let out = [];
- for (let item of text.split(/\n\n+/)) {
- out.push('<div class="paragraph-spacing"></div>');
- out.push($sanitize(item));
- }
- out.splice(0, 1);
- return $sce.trustAsHtml(out.join("\n"));
- };
-
function getConfigWidgetModeInternal(item, val) {
if (angular.element($document[0].activeElement).hasClass("form-control") && item.widgetMode) {
// don't switch mode in mid-edit, e.g. if you are manually typing $brooklyn:component("x").config("y")
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 3a6e045..68fd6e3 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
@@ -32,7 +32,7 @@
cursor: pointer;
transition: 0.1s ease all;
&:hover {
- color: @brand-primary;
+ color: @brand-primary !important;
}
}
.remove-affordance() {
@@ -903,6 +903,15 @@
order: 99;
}
}
+
+ .type-description {
+ .toolbar-button-affordance();
+ padding-top: 1ex;
+ float: right;
+ &.active {
+ color: @gray;
+ }
+ }
}
.popover.spec-editor-popover {
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 6c46db0..19b0371 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
@@ -41,16 +41,32 @@
<img ng-src="{{model.icon}}" alt="{{model | entityName}} logo" class="media-object" />
</div>
<div class="media-body panel-header-body">
- <div title="{{ model.miscData.get('typeName') }}"><i class="fa fa-bookmark panel-header-icon"></i><samp class="entity-type-header">{{model.type}}</samp> <span class="label label-primary version">{{model | entityVersion}}</span></div>
+ <div title="{{ model.miscData.get('typeName') }}">
+ <i class="fa fa-question-circle type-description"
+ ng-class="{ 'active': specEditor.descriptionVisible }"
+ title="{{ specEditor.descriptionVisible ? 'Hide description' : 'Show description' }}"
+ ng-if="modelDescription.isPresent"
+ ng-click="specEditor.descriptionVisible = !specEditor.descriptionVisible"></i>
+ <i class="fa fa-bookmark panel-header-icon"></i><samp class="entity-type-header">{{model.type}}</samp>
+ <span class="label label-primary version">{{model | entityVersion}}</span>
+ </div>
<div ng-if="['POLICY', 'ENRICHER'].indexOf(model.family.id) === -1" class="identifier">
<i class="fa fa-id-card-o panel-header-icon"></i>
<input class="form-control editable" ng-model="model.id" placeholder="(no reference ID)" blur-on-enter />
</div>
+ <md-if-oneline ng-show="specEditor.descriptionVisible && modelDescription.isNonMultiline" data="modelDescription"></md-if-oneline>
</div>
</div>
</div>
</section>
+<br-collapsible state="true" ng-show="specEditor.descriptionVisible && modelDescription.isMultiline">
+ <heading>Description</heading>
+
+ <div style="margin-left: 3px;">
+ <md-if-multiline ng-show="specEditor.descriptionVisible" data="modelDescription"></md-if-multiline>
+ </div>
+</br-collapsible>
<!-- ENTITY PARAMETERS -->
<br-collapsible state="state.parameters.open" ng-if="!model.parent"> <!-- the ng-if is needed to make state update?! -->
@@ -672,7 +688,9 @@
<p><i class="mini-icon fa fa-fw fa-cog"></i> <samp class="type-symbolic-name">{{item.name}}</samp>
<span class="config-type label-color column-for-type oneline label label-success">{{item.type}}</span></p>
</div>
- <p class="quick-info-description" ng-if="item.description" ng-bind-html="specEditor.descriptionHtml(item.description)"></p>
+ <p class="quick-info-description">
+ <md-field raw-item="item"/>
+ </p>
<div class="quick-info-metadata config-default" ng-if="item.defaultValue"></i>Default value: <samp>{{item.defaultValue}}</samp></div>
</div>
@@ -686,7 +704,9 @@
<p><i class="mini-icon fa fa-fw fa-cog"></i> <samp class="type-symbolic-name">{{item.name}}</samp>
<span class="config-type label-color column-for-type oneline label label-success">{{item.type}}</span></p>
</div>
- <p class="quick-info-description" ng-if="item.description" ng-bind-html="specEditor.descriptionHtml(item.description)"></p>
+ <p class="quick-info-description" ng-if="item.description">
+ <md-field raw-item="item"/>
+ </p>
<div class="quick-info-metadata config-default" ng-if="item.defaultValue"></i>Default value: <samp>{{item.defaultValue}}</samp></div>
<div class="quick-info-metadata config-required" ng-if="item.constraints.required"><i>This field is required.</div>
</div>
diff --git a/ui-modules/blueprint-composer/app/index.js b/ui-modules/blueprint-composer/app/index.js
index e45c07f..7504627 100755
--- a/ui-modules/blueprint-composer/app/index.js
+++ b/ui-modules/blueprint-composer/app/index.js
@@ -35,6 +35,7 @@
import brooklynUserManagement from 'brooklyn-ui-utils/user-management/user-management';
import brYamlEditor from 'brooklyn-ui-utils/yaml-editor/yaml-editor';
import brUtils from 'brooklyn-ui-utils/utils/general';
+import mdHelper from 'brooklyn-ui-utils/md-helper';
import brSpecEditor from './components/spec-editor/spec-editor.directive';
import brooklynCatalogSaver from './components/catalog-saver/catalog-saver.directive';
@@ -79,7 +80,7 @@
angular.module('brooklynBlueprintComposer', [ngAnimate, ngResource, ngCookies, ngClipboard, uiRouter, 'ui.router.state.events', brCore,
brServerStatus, brAutoFocus, brIconGenerator, brInterstitialSpinner, brooklynModuleLinks, brooklynUserManagement,
- brYamlEditor, brUtils, brSpecEditor, brooklynCatalogSaver, brooklynApi, bottomSheet, stackViewer, brDragndrop,
+ brYamlEditor, brUtils, brSpecEditor, brooklynCatalogSaver, brooklynApi, bottomSheet, stackViewer, brDragndrop, mdHelper,
customActionDirective, customConfigSuggestionDropdown, paletteApiProvider, paletteServiceProvider, blueprintLoaderApiProvider,
breadcrumbs, catalogSelector, designer, objectCache, entityFilters, locationFilter, actionService, tabService, composerOverrides, blueprintService,
dslService, paletteDragAndDropService, recentlyUsedService, scriptTagDecorator, brandAngularJs])
diff --git a/ui-modules/utils/md-helper/index.js b/ui-modules/utils/md-helper/index.js
index d462c3b..4890749 100644
--- a/ui-modules/utils/md-helper/index.js
+++ b/ui-modules/utils/md-helper/index.js
@@ -37,22 +37,16 @@
scope: {
data: '<',
rawData: '<',
+ rawItem: '<',
},
+ controller: ['$scope', populateData],
template: `
<div>
<md-if-oneline data="data"></md-if-oneline>
<md-if-multiline data="data"></md-if-multiline>
</div>
`,
- controller: ['$scope', function ($scope) {
- if ($scope.rawData && !$scope.data) {
- $scope.data = analyze($scope.rawData);
- }
- }],
};
-
- function link(scope, element, attrs) {
- }
}
// prints out one line of data -- in future could use markdown formatting, but currently does not
@@ -61,14 +55,14 @@
restrict: 'E',
scope: {
data: '<',
+ rawData: '<',
+ rawItem: '<',
},
+ controller: ['$scope', populateData],
template: `
<span>{{::data.oneline}}</span>
`,
};
-
- function link(scope, element, attrs) {
- }
}
// prints out full, formatted, _if_ it is one line of data
@@ -77,7 +71,10 @@
restrict: 'E',
scope: {
data: '<',
+ rawData: '<',
+ rawItem: '<',
},
+ controller: ['$scope', populateData],
template: `
<div ng-if="data.isNonMultiline">
<p ng-if="data.unformatted">{{data.unformatted}}</p>
@@ -85,9 +82,6 @@
</div>
`,
};
-
- function link(scope, element, attrs) {
- }
}
// prints out all the data, formatted, if multiline
@@ -96,19 +90,37 @@
restrict: 'E',
scope: {
data: '<',
+ rawData: '<',
+ rawItem: '<',
},
+ controller: ['$scope', populateData],
+ // for multiline, collapse margin from children eg an <h1> first element, inserting then removing a 24px margin
template: `
<div ng-if="data.isMultiline">
<pre ng-if="data.unformatted">{{data.unformatted}}</pre>
- <div ng-if="data.markdownFormatted" ng-bind-html="data.markdownFormatted"></div>
+ <div ng-if="data.markdownFormatted" style="margin-top: -24px;"><div style="margin-top: 24px;" ng-bind-html="data.markdownFormatted"></div></div>
</div>
`,
};
}
+function nameFieldValues(src) {
+ src = src || {};
+ return ['symbolicName', 'displayName', 'typeName', 'name'].map(x => src[x]);
+}
+
+function populateData($scope) {
+ if (!$scope.data) {
+ if (!$scope.rawData && $scope.rawItem) {
+ $scope.rawData = $scope.rawItem.description;
+ }
+ $scope.data = analyze($scope.rawData, nameFieldValues($scope.rawItem));
+ }
+}
+
export function analyzeDescription(input) {
input = input || {};
- return analyze(input.description, [input.symbolicName, input.displayName, input.name]);
+ return analyze(input.description, nameFieldValues(input));
}
export function analyze(field, names) {
@@ -121,6 +133,7 @@
try {
result.markdownFormatted = marked(field);
} catch (e) {
+ console.log("could not convert markdown; treading as unformatted", e);
// not markdown
result.unformatted = field;
}