summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Karikh <pkarikh@mirantis.com>2015-06-25 19:14:03 +0300
committerPaul Karikh <pkarikh@mirantis.com>2015-07-06 14:52:47 +0300
commitbf942fef1c1aa7de7fe1891aa77823d1c8374540 (patch)
tree33b84a0bb144ae3d48f35165a9321d46c984cd4f
parenta08c69b0d29378602f7351d58f18b504273c4acc (diff)
Add FAQ and glossary
This patch adds FAQ and glossary to the readme.md file. Also this patch adds documentation for Merlin directives. Also this patch grunt task for generation html from markdown. To run this task run 'grunt md' from the Merlin directory. Change-Id: Ifd98fe4d9fa61bf5b7bbd71361763caa93e7ed3e
Notes
Notes (review): Verified+2: Jenkins Code-Review+2: Timur Sufiev <tsufiev@mirantis.com> Workflow+1: Timur Sufiev <tsufiev@mirantis.com> Submitted-by: Jenkins Submitted-at: Mon, 06 Jul 2015 12:26:59 +0000 Reviewed-on: https://review.openstack.org/195661 Project: stackforge/merlin Branch: refs/heads/master
-rw-r--r--Gruntfile.js12
-rw-r--r--README.md67
-rw-r--r--merlin/static/merlin/js/merlin.directives.js21
-rw-r--r--package.json1
4 files changed, 100 insertions, 1 deletions
diff --git a/Gruntfile.js b/Gruntfile.js
index 9112234..9efe96a 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -52,12 +52,24 @@ module.exports = function(grunt){
52 // run tests once instead of continuously 52 // run tests once instead of continuously
53 singleRun: true 53 singleRun: true
54 } 54 }
55 },
56 markdown: {
57 all: {
58 files: [{
59 expand: true,
60 src: './README.md',
61 dest: './',
62 ext: '.html'
63 }]
64 }
55 } 65 }
56 }); 66 });
57 grunt.loadNpmTasks('grunt-karma'); 67 grunt.loadNpmTasks('grunt-karma');
58 grunt.loadNpmTasks('grunt-contrib-concat'); 68 grunt.loadNpmTasks('grunt-contrib-concat');
59 grunt.loadNpmTasks('grunt-contrib-uglify'); 69 grunt.loadNpmTasks('grunt-contrib-uglify');
70 grunt.loadNpmTasks('grunt-markdown');
60 grunt.registerTask('test:unit', [ 71 grunt.registerTask('test:unit', [
61 'karma:unit' 72 'karma:unit'
62 ]); 73 ]);
74 grunt.registerTask('md', ['markdown:all'])
63}; 75};
diff --git a/README.md b/README.md
index dd26d39..759ea82 100644
--- a/README.md
+++ b/README.md
@@ -50,4 +50,69 @@ the **Project** dashboard, **Orchestration** panel group.
504. ``sudo npm install -g grunt-cli`` 504. ``sudo npm install -g grunt-cli``
515. ``grunt test:unit`` 515. ``grunt test:unit``
52 52
53For more info please refer to https://wiki.openstack.org/wiki/Merlin 53# Glossary:
54
55 * Schema - is a main object for describing structure of a model. This object describes how fields and containers are bounded between themselfs, and how the are being modified.
56Merlin use schema to validate user input, render forms, fields and models. If you want to define, that if user sets field "type" for "action", that first field in the form should be "Base" - scheme is the place where you should to define it.
57 * Model - is a prototype for field. Model could describe a different types of fields: strings, text (large string), numer, dictionary, frozendictionary (immutable dictionary), and so on.
58 * Using models helps to render and validate fields. Uou can extend existing models and create your custom field types. Barricade.js object becames an Merlin object when we add modelMixin.
59Field - is an atom of form. Should be inherited from some model (Merlin model or your custom model).
60 * Panel - visual group of containers.
61 * Container - Barricade-specific object type (immutable objects, arrays, mutable objects).
62
63
64 ### The final structure of UI is defined by:
65 * the schema
66 * the actual data this schema is paired with to create Barricade object
67 * filters and directives being used in an html for rendering the Barricade object provided on the scope
68
69
70 ### Merlin filters:
71 * extractPanels, extractItems, extractRows - used to unpack data from Barricade.js format
72into format for convenient template rendering. Also, you can apply a few filters for one Barricade object.
73
74# FAQ
75 ### But where are any controllers?
76The are in the app. –°ore Merlin code currently doesn't define any controllers because all logic is put into the model, i.e. Barricade objects".
77
78 ### How can I use Merlin in my app?
79You can take a look at the `/mistral/` directory, which contains Workbook builder app based on Merlin. There is some django-code to render view to show dashboard in the Horizon.
80And in the `merlin/extensions/mistral/static/mistral` is Merlin based code. `templates/fields` contains definition of additional (Mistral-specific) types of fields.
81You can take a look at `merlin/extensions/` directory. In the `/enabled/` dir there is typical panel file to add new panel into Horizon Dashboard.
82`mistral.init.js` contains fetching custom mistral templates for fields. In this file Angular 'mistral' module is initialized first time, so it should be loaded before any other scripts defining entities within 'mistral' module.
83`mistral.workbook.controllers.js` - contains main controller which contains functions for domain-specific actions. For example, actions for creating and initializing Action and Workflow objects.
84
85Lets take a look at the typical definition.
86```
87'base-input': {
88 '@class': fields.dictionary.extend({ // which model we are going to use as prototype
89 create: function(json, parameters) {
90 var self = fields.dictionary.create.call(this, json, parameters);
91 self.setType('frozendict');
92 return self;
93 }
94 }, {
95 '@required': false,
96 '?': { //'?' is a marker for Barricade MutableObject
97 '@class': fields.string.extend({}, {
98 '@meta': { '@meta' tells Merlin how to render it
99 'row': 0
100 }
101 })
102 },
103 '@meta': {
104 'index': 2,
105 'title': 'Base Input'
106 }
107 })
108},
109```
110
111 ### How does Merlin know how to render field, panel or group?
112Merlin uses templates for this. Each type of field has its own template with html and css-markup, so you can define filters, directives, on-click events, and rules for filling variables for each type of field.
113The same mechanism is implemented for groups and panels.
114
115 ### How does Merlin gets/sets model value with barricade.js?
116Each model has getter/setter, so, when you access to model.value field, if you doing it without param, you calling getter, if you pass any param - you calling a setter. For proper work of this feature we have to use ng-model-options="{getterSetter: true}" ability of angular.js.
117Currently angular-ui bootstrap library has a bug which doesn't allow use getterSetter: true, and since it is a problem for autosuggestion feature, we filed a bug (and a patch) to the angular-ui repo (ling), and until it will not be released, we managed to use patched version of this library.
118That's why we have ui-bootstrap-tpls-0.13.0.patched.js file in custom-lib directory.
diff --git a/merlin/static/merlin/js/merlin.directives.js b/merlin/static/merlin/js/merlin.directives.js
index 5f0f306..dc83fce 100644
--- a/merlin/static/merlin/js/merlin.directives.js
+++ b/merlin/static/merlin/js/merlin.directives.js
@@ -5,6 +5,12 @@
5 'use strict'; 5 'use strict';
6 6
7 angular.module('merlin') 7 angular.module('merlin')
8 /*
9 * Allows to edit field name in-place.
10 * For example, you have a field named 'Input 1' and you want to replace this name with "Base input" value.
11 * If you add editable directive to such field, you will get a marker icon near this field,
12 * and with clicking on this icon you can type new name and save or discard changes.
13 * */
8 .directive('editable', function() { 14 .directive('editable', function() {
9 return { 15 return {
10 restrict: 'E', 16 restrict: 'E',
@@ -58,6 +64,9 @@
58 } 64 }
59 }; 65 };
60 }) 66 })
67 /*
68 * this directive auto-sets the focus to an input field once it is shown.
69 * */
61 .directive('showFocus', function($timeout) { 70 .directive('showFocus', function($timeout) {
62 return function(scope, element, attrs) { 71 return function(scope, element, attrs) {
63 scope.$watch(attrs.showFocus, function(newValue) { 72 scope.$watch(attrs.showFocus, function(newValue) {
@@ -67,6 +76,9 @@
67 }); 76 });
68 } 77 }
69 }) 78 })
79 /*
80 * tells Merlin to render this element as a panel.
81 * */
70 .directive('panel', function($parse) { 82 .directive('panel', function($parse) {
71 return { 83 return {
72 restrict: 'E', 84 restrict: 'E',
@@ -81,6 +93,9 @@
81 } 93 }
82 } 94 }
83 }) 95 })
96 /*
97 * tells Merlin to render this element as a group with ability to collapse.
98 * */
84 .directive('collapsibleGroup', function() { 99 .directive('collapsibleGroup', function() {
85 return { 100 return {
86 restrict: 'E', 101 restrict: 'E',
@@ -102,6 +117,9 @@
102 } 117 }
103 } 118 }
104 }) 119 })
120 /*
121 * sets up the DOM nodes related to validation of model being edited in this widget (and specifies the name of this model on scope).
122 * */
105 .directive('validatableWith', function($parse) { 123 .directive('validatableWith', function($parse) {
106 return { 124 return {
107 restrict: 'A', 125 restrict: 'A',
@@ -132,6 +150,9 @@
132 } 150 }
133 } 151 }
134 }) 152 })
153 /*
154 * retrieves a template by its name which is the same as model's type and renders it, recursive <typed-field></..>-s are possible.
155 * */
135 .directive('typedField', ['$compile', 'merlin.templates', 156 .directive('typedField', ['$compile', 'merlin.templates',
136 function($compile, templates) { 157 function($compile, templates) {
137 function updateAutoCompletionDirective(template) { 158 function updateAutoCompletionDirective(template) {
diff --git a/package.json b/package.json
index f0fc170..2567f56 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
16 "grunt-eslint": "7.0.1", 16 "grunt-eslint": "7.0.1",
17 "grunt-html2js": "0.2.9", 17 "grunt-html2js": "0.2.9",
18 "grunt-karma": "0.10.1", 18 "grunt-karma": "0.10.1",
19 "grunt-markdown": "^0.7.0",
19 "grunt-open": "0.2.3", 20 "grunt-open": "0.2.3",
20 "grunt-protractor-runner": "1.1.4", 21 "grunt-protractor-runner": "1.1.4",
21 "grunt-shell": "1.1.1", 22 "grunt-shell": "1.1.1",