praxis 0.18.1 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +57 -1
- data/Gemfile +2 -1
- data/README.md +21 -27
- data/lib/api_browser/app/index.html +3 -3
- data/lib/api_browser/app/js/app.js +23 -3
- data/lib/api_browser/app/js/controllers/action.js +33 -21
- data/lib/api_browser/app/js/controllers/controller.js +3 -25
- data/lib/api_browser/app/js/controllers/menu.js +61 -51
- data/lib/api_browser/app/js/controllers/trait.js +10 -0
- data/lib/api_browser/app/js/controllers/type.js +8 -5
- data/lib/api_browser/app/js/directives/fixed_if_fits.js +9 -2
- data/lib/api_browser/app/js/directives/menu_item.js +59 -0
- data/lib/api_browser/app/js/directives/readable_list.js +87 -0
- data/lib/api_browser/app/js/directives/url.js +16 -0
- data/lib/api_browser/app/js/factories/Configuration.js +1 -2
- data/lib/api_browser/app/js/factories/Documentation.js +49 -7
- data/lib/api_browser/app/js/factories/PageInfo.js +9 -0
- data/lib/api_browser/app/js/factories/normalize_attributes.js +1 -2
- data/lib/api_browser/app/js/factories/template_for.js +9 -4
- data/lib/api_browser/app/sass/modules/_sidebar.scss +54 -15
- data/lib/api_browser/app/sass/praxis.scss +4 -0
- data/lib/api_browser/app/views/action.html +72 -41
- data/lib/api_browser/app/views/builtin/field-selector.html +24 -0
- data/lib/api_browser/app/views/controller.html +9 -10
- data/lib/api_browser/app/views/directives/menu_item.html +8 -0
- data/lib/api_browser/app/views/directives/url.html +3 -0
- data/lib/api_browser/app/views/layout.html +2 -2
- data/lib/api_browser/app/views/menu.html +8 -14
- data/lib/api_browser/app/views/navbar.html +1 -1
- data/lib/api_browser/app/views/trait.html +13 -0
- data/lib/api_browser/app/views/type/details.html +1 -1
- data/lib/api_browser/app/views/type.html +1 -1
- data/lib/api_browser/app/views/types/embedded/field-selector.html +13 -0
- data/lib/api_browser/app/views/types/label/primitive.html +1 -1
- data/lib/api_browser/app/views/types/standalone/array.html +3 -0
- data/lib/praxis/action_definition.rb +15 -2
- data/lib/praxis/collection.rb +17 -5
- data/lib/praxis/controller.rb +12 -3
- data/lib/praxis/docs/generator.rb +11 -7
- data/lib/praxis/extensions/field_expansion.rb +59 -0
- data/lib/praxis/extensions/field_selection/field_selector.rb +125 -0
- data/lib/praxis/extensions/field_selection.rb +10 -0
- data/lib/praxis/extensions/mapper_selectors.rb +16 -0
- data/lib/praxis/extensions/rendering.rb +43 -0
- data/lib/praxis/links.rb +1 -0
- data/lib/praxis/media_type.rb +87 -3
- data/lib/praxis/media_type_collection.rb +1 -1
- data/lib/praxis/media_type_identifier.rb +6 -1
- data/lib/praxis/plugins/praxis_mapper_plugin.rb +29 -10
- data/lib/praxis/restful_doc_generator.rb +11 -8
- data/lib/praxis/tasks/api_docs.rb +6 -5
- data/lib/praxis/types/multipart_array.rb +1 -1
- data/lib/praxis/version.rb +1 -1
- data/lib/praxis.rb +5 -0
- data/praxis.gemspec +4 -3
- data/spec/api_browser/factories/configuration_spec.js +32 -0
- data/spec/api_browser/factories/documentation_spec.js +75 -25
- data/spec/api_browser/factories/normalize_attributes_spec.js +0 -5
- data/spec/praxis/{types/collection_spec.rb → collection_spec.rb} +36 -23
- data/spec/praxis/extensions/field_expansion_spec.rb +96 -0
- data/spec/praxis/extensions/field_selection/field_selector_spec.rb +92 -0
- data/spec/praxis/extensions/rendering_spec.rb +63 -0
- data/spec/praxis/links_spec.rb +6 -0
- data/spec/praxis/media_type_collection_spec.rb +0 -1
- data/spec/praxis/media_type_identifier_spec.rb +15 -1
- data/spec/praxis/media_type_spec.rb +101 -3
- data/spec/praxis/plugins/praxis_mapper_plugin_spec.rb +33 -24
- data/spec/praxis/request_stages/request_stage_spec.rb +1 -1
- data/spec/praxis/types/multipart_array_spec.rb +14 -4
- data/spec/spec_app/app/controllers/instances.rb +6 -1
- data/spec/spec_app/config/environment.rb +2 -1
- data/spec/spec_app/design/resources/instances.rb +1 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/support/spec_media_types.rb +224 -1
- metadata +50 -16
@@ -0,0 +1,87 @@
|
|
1
|
+
app.factory('Repeater', function() {
|
2
|
+
function Repeater(expression) {
|
3
|
+
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
|
4
|
+
|
5
|
+
var lhs = match[1];
|
6
|
+
this.rhs = match[2];
|
7
|
+
this.aliasAs = match[3];
|
8
|
+
this.trackByExp = match[4];
|
9
|
+
|
10
|
+
match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
|
11
|
+
|
12
|
+
this.valueIdentifier = match[3] || match[1];
|
13
|
+
this.keyIdentifier = match[2];
|
14
|
+
}
|
15
|
+
|
16
|
+
Repeater.prototype.$watch = function(fn) {
|
17
|
+
this.$scope.$watchCollection(this.rhs, fn);
|
18
|
+
};
|
19
|
+
|
20
|
+
Repeater.prototype.$transclude = function(length, value, key, index, fn) {
|
21
|
+
var self = this;
|
22
|
+
self._transclude(function(clone, scope) {
|
23
|
+
scope[self.valueIdentifier] = value;
|
24
|
+
if (self.keyIdentifier) scope[self.keyIdentifier] = key;
|
25
|
+
scope.$index = index;
|
26
|
+
scope.$first = (index === 0);
|
27
|
+
scope.$last = (index === (length - 1));
|
28
|
+
scope.$middle = !(scope.$first || scope.$last);
|
29
|
+
// jshint bitwise: false
|
30
|
+
scope.$odd = !(scope.$even = (index&1) === 0);
|
31
|
+
// jshint bitwise: true
|
32
|
+
fn(clone, scope);
|
33
|
+
});
|
34
|
+
};
|
35
|
+
|
36
|
+
return {
|
37
|
+
compile: function(repeatAttr, linkFn) {
|
38
|
+
return function(element, attrs) {
|
39
|
+
var expression = attrs[repeatAttr];
|
40
|
+
var repeater = new Repeater(expression);
|
41
|
+
return function($scope, $element, $attr, ctrl, $transclude) {
|
42
|
+
repeater._transclude = $transclude;
|
43
|
+
repeater.$scope = $scope;
|
44
|
+
linkFn($scope, $element, $attr, ctrl, repeater);
|
45
|
+
};
|
46
|
+
};
|
47
|
+
}
|
48
|
+
};
|
49
|
+
});
|
50
|
+
app.directive('readableList', function(Repeater) {
|
51
|
+
|
52
|
+
return {
|
53
|
+
restrict: 'E',
|
54
|
+
transclude: true,
|
55
|
+
compile: Repeater.compile('repeat', function($scope, $element, $attr, ctrl, $repeat) {
|
56
|
+
$repeat.$watch(function(inputList) {
|
57
|
+
$element.empty();
|
58
|
+
if (inputList.length == 1) {
|
59
|
+
$repeat.$transclude(1, inputList[0], null, 0, function(clone) {
|
60
|
+
$element.append(clone);
|
61
|
+
});
|
62
|
+
} else {
|
63
|
+
var finalJoin = ' and ';
|
64
|
+
|
65
|
+
var join = ', ',
|
66
|
+
arr = inputList.slice(0),
|
67
|
+
last = arr.pop(),
|
68
|
+
beforeLast = arr.pop();
|
69
|
+
|
70
|
+
_.each(arr, function(data, index) {
|
71
|
+
$repeat.$transclude(inputList.length, data, null, index, function(clone) {
|
72
|
+
$element.append(clone);
|
73
|
+
$element.append(document.createTextNode(join));
|
74
|
+
});
|
75
|
+
});
|
76
|
+
$repeat.$transclude(inputList.length, beforeLast, null, inputList.length - 2, function(clone) {
|
77
|
+
$element.append(clone);
|
78
|
+
$element.append(document.createTextNode(finalJoin));
|
79
|
+
});
|
80
|
+
$repeat.$transclude(inputList.length, last, null, inputList.length - 1, function(clone) {
|
81
|
+
$element.append(clone);
|
82
|
+
});
|
83
|
+
}
|
84
|
+
});
|
85
|
+
})
|
86
|
+
};
|
87
|
+
});
|
@@ -0,0 +1,16 @@
|
|
1
|
+
/**
|
2
|
+
* This directive is responsible to render a URL for an action
|
3
|
+
*/
|
4
|
+
app.directive('url', function() {
|
5
|
+
return {
|
6
|
+
restrict: 'EA',
|
7
|
+
scope: {
|
8
|
+
action: '=',
|
9
|
+
example: '@'
|
10
|
+
},
|
11
|
+
templateUrl: 'views/directives/url.html',
|
12
|
+
link: function(scope, element, attrs) {
|
13
|
+
scope.showExample = scope.example == 'example' || scope.example == 'true' || 'example' in attrs;
|
14
|
+
}
|
15
|
+
};
|
16
|
+
});
|
@@ -7,7 +7,6 @@ app.provider('Configuration', function() {
|
|
7
7
|
this.$get = function() {
|
8
8
|
return this;
|
9
9
|
};
|
10
|
-
}).run(function(Configuration, $rootScope
|
10
|
+
}).run(function(Configuration, $rootScope) {
|
11
11
|
_.extend($rootScope, _.omit(Configuration, '$get'));
|
12
|
-
$document[0].title = Configuration.title;
|
13
12
|
});
|
@@ -1,13 +1,55 @@
|
|
1
|
-
|
1
|
+
/**
|
2
|
+
* This service gives access to the documentation metadata
|
3
|
+
*/
|
4
|
+
app.factory('Documentation', function($http, $q) {
|
5
|
+
var versions = $q.when($http.get('api/index-new.json', { cache: true }).then(function(data) {
|
6
|
+
return $q.all(_.map(data.data.versions, function(version) {
|
7
|
+
return $http.get('api/' + version + '.json', {cache: true}).then(function(versionData) {
|
8
|
+
return [version, versionData.data];
|
9
|
+
});
|
10
|
+
})).then(_.zipObject);
|
11
|
+
}));
|
12
|
+
|
2
13
|
return {
|
3
|
-
|
4
|
-
|
14
|
+
/**
|
15
|
+
* Returns an array of version strings
|
16
|
+
*/
|
17
|
+
versions: function() {
|
18
|
+
return versions.then(_.keys);
|
5
19
|
},
|
6
|
-
|
7
|
-
|
20
|
+
/**
|
21
|
+
* Returns a list of controllers and types, useful for generating navigation
|
22
|
+
*/
|
23
|
+
items: function(version) {
|
24
|
+
return versions.then(function(v) { return v[version]; });
|
8
25
|
},
|
9
|
-
|
10
|
-
|
26
|
+
/**
|
27
|
+
* Returns description of a controller
|
28
|
+
*/
|
29
|
+
controller: function(version, name) {
|
30
|
+
return this.items(version).then(function(v) {
|
31
|
+
var controller = v.resources[name];
|
32
|
+
controller.id = name;
|
33
|
+
return controller;
|
34
|
+
});
|
35
|
+
},
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Returns a description of a type
|
39
|
+
*/
|
40
|
+
type: function(version, name) {
|
41
|
+
return versions.then(function(v) {
|
42
|
+
return v[version].schemas[name];
|
43
|
+
});
|
44
|
+
},
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Returns a description of a trait
|
48
|
+
*/
|
49
|
+
trait: function(version, name) {
|
50
|
+
return versions.then(function(v) {
|
51
|
+
return v[version].traits[name];
|
52
|
+
});
|
11
53
|
}
|
12
54
|
};
|
13
55
|
});
|
@@ -2,11 +2,10 @@ app.factory('normalizeAttributes', function() {
|
|
2
2
|
function normalize(type, attributes, parent) {
|
3
3
|
_.forEach(attributes, function(attribute, name) {
|
4
4
|
var path = parent.concat([name]);
|
5
|
-
var example = JSON.stringify(_.get(type.example, path), null, 2);
|
6
5
|
if (!attribute.options) attribute.options = {};
|
7
|
-
if (example) attribute.options.example = example;
|
8
6
|
if (attribute.values != null) attribute.options.values = attribute.values;
|
9
7
|
if (attribute.default != null) attribute.options.default = attribute.default;
|
8
|
+
if (attribute.example != null) attribute.options.example = attribute.example;
|
10
9
|
if (attribute.type && attribute.type.attributes) {
|
11
10
|
normalize(type, attribute.type.attributes, path);
|
12
11
|
}
|
@@ -36,6 +36,8 @@ app.provider('templateFor', function() {
|
|
36
36
|
switch ($family) {
|
37
37
|
case 'hash':
|
38
38
|
return 'views/types/standalone/struct.html';
|
39
|
+
case 'array':
|
40
|
+
return 'views/types/standalone/array.html';
|
39
41
|
default:
|
40
42
|
return 'views/types/standalone/default.html';
|
41
43
|
}
|
@@ -48,6 +50,9 @@ app.provider('templateFor', function() {
|
|
48
50
|
if ($type === 'Links') {
|
49
51
|
return 'views/types/embedded/links.html';
|
50
52
|
}
|
53
|
+
if ($type === 'Praxis::Extensions::FieldSelection::FieldSelector') {
|
54
|
+
return 'views/types/embedded/field-selector.html';
|
55
|
+
}
|
51
56
|
switch ($family) {
|
52
57
|
case 'hash':
|
53
58
|
return 'views/types/embedded/struct.html';
|
@@ -60,14 +65,14 @@ app.provider('templateFor', function() {
|
|
60
65
|
this.register(function labelResolver($typeDefinition, $requestedTemplate, primitives) {
|
61
66
|
'ngInject';
|
62
67
|
if ($requestedTemplate === 'label') {
|
63
|
-
if (
|
64
|
-
|
65
|
-
} else if ( $typeDefinition.member_attribute !== undefined ) {
|
66
|
-
if ( _.contains(primitives, $typeDefinition.member_attribute.type.name)){
|
68
|
+
if ( $typeDefinition.member_attribute !== undefined) {
|
69
|
+
if ($typeDefinition.member_attribute.anonymous || _.contains(primitives, $typeDefinition.name)) {
|
67
70
|
return 'views/types/label/primitive_collection.html';
|
68
71
|
} else{
|
69
72
|
return 'views/types/label/type_collection.html';
|
70
73
|
}
|
74
|
+
} else if ($typeDefinition.anonymous || _.contains(primitives, $typeDefinition.name)) {
|
75
|
+
return 'views/types/label/primitive.html';
|
71
76
|
} else if ($typeDefinition.link_to) {
|
72
77
|
return 'views/types/label/link.html';
|
73
78
|
}
|
@@ -3,9 +3,6 @@
|
|
3
3
|
// ------------------------------
|
4
4
|
|
5
5
|
.sidebar {
|
6
|
-
@media (min-width: $screen-sm-min) {
|
7
|
-
width: 160px;
|
8
|
-
}
|
9
6
|
@media (min-width: $screen-lg-min) {
|
10
7
|
width: 250px;
|
11
8
|
}
|
@@ -20,25 +17,66 @@
|
|
20
17
|
}
|
21
18
|
|
22
19
|
.sidebar {
|
20
|
+
.open .dropdown-menu {
|
21
|
+
margin-left: 15px;
|
22
|
+
}
|
23
23
|
.list-group {
|
24
24
|
margin-bottom: 0;
|
25
25
|
margin-top: 0;
|
26
|
-
|
27
|
-
.list-group-item {
|
28
|
-
border-width: 1px 0;
|
29
|
-
word-break: break-word;
|
30
|
-
&:first-of-type {
|
26
|
+
& > menu-item:first-of-type > .menu-item {
|
31
27
|
border-radius: 0;
|
32
28
|
border-top: 0 none;
|
33
29
|
}
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
}
|
31
|
+
.action {
|
32
|
+
background: $table-bg-accent;
|
33
|
+
font-size: 11px;
|
34
|
+
font-weight: bolder;
|
35
|
+
}
|
36
|
+
.menu-item {
|
37
|
+
position: relative;
|
38
|
+
display: block;
|
39
|
+
// Place the border on the list items and negative margin up for better styling
|
40
|
+
margin-bottom: -1px;
|
41
|
+
background-color: $list-group-bg;
|
42
|
+
border: 1px solid $list-group-border;
|
43
|
+
border-width: 1px 0;
|
44
|
+
word-break: break-word;
|
45
|
+
a {
|
46
|
+
display: block;
|
47
|
+
padding: 10px 15px;
|
48
|
+
// Hover state
|
49
|
+
&:hover,
|
50
|
+
&:focus {
|
51
|
+
text-decoration: none;
|
52
|
+
background-color: $list-group-hover-bg;
|
53
|
+
}
|
54
|
+
|
55
|
+
// Active class on item itself, not parent
|
56
|
+
&.active,
|
57
|
+
&.active:hover,
|
58
|
+
&.active:focus {
|
59
|
+
z-index: 2; // Place active items above their siblings for proper border styling
|
60
|
+
color: $list-group-active-color;
|
61
|
+
background-color: $list-group-active-bg;
|
62
|
+
border-color: $list-group-active-border;
|
63
|
+
font-weight: bolder;
|
64
|
+
}
|
39
65
|
}
|
40
|
-
|
41
|
-
|
66
|
+
.menu-item {
|
67
|
+
a.action { padding: 10px 2.5rem; }
|
68
|
+
a.main { padding: 10px 2rem; }
|
69
|
+
a.main::before {
|
70
|
+
content: "↳"
|
71
|
+
}
|
72
|
+
.menu-item {
|
73
|
+
a.action { padding: 10px 3.5rem; }
|
74
|
+
a.main { padding: 10px 3rem; }
|
75
|
+
.menu-item {
|
76
|
+
a.action { padding: 10px 4.5rem; }
|
77
|
+
a.main { padding: 10px 4rem; }
|
78
|
+
}
|
79
|
+
}
|
42
80
|
}
|
43
81
|
}
|
44
82
|
}
|
@@ -73,6 +111,7 @@
|
|
73
111
|
a {
|
74
112
|
border-bottom: 0;
|
75
113
|
font-size: 12px;
|
114
|
+
padding: 10px 5px;
|
76
115
|
&:hover {
|
77
116
|
background-color: #fff;
|
78
117
|
border-color: transparent;
|
@@ -4,72 +4,103 @@
|
|
4
4
|
<div ng-if="action">
|
5
5
|
<div class="row">
|
6
6
|
<div class="col-lg-12">
|
7
|
-
<
|
8
|
-
{{ action.name }}
|
9
|
-
</
|
10
|
-
<
|
11
|
-
<span class="label label-default verb" ng-class="url.verb | lowercase">{{ url.verb }}</span> <b>{{ url.path }}</b>
|
12
|
-
</p>
|
7
|
+
<h1>
|
8
|
+
<a ui-sref="root.controller({version: apiVersion, controller: controller.id})">{{controller.display_name}}</a> » {{ action.name }}
|
9
|
+
</h1>
|
10
|
+
<url action="action"></url>
|
13
11
|
<p ng-bind-html="action.description | markdown"></p>
|
12
|
+
<p class="traits" ng-if="action.traits.length > 0">
|
13
|
+
This action is
|
14
|
+
<readable-list repeat="trait in action.traits"><a ui-sref="root.trait({version: apiVersion, trait: trait})">{{trait}}</a></readable-list>.
|
15
|
+
</p>
|
14
16
|
</div>
|
15
17
|
</div>
|
16
18
|
|
17
19
|
<div class="row" ng-if="action.headers.type.attributes">
|
18
20
|
<div class="col-lg-12">
|
19
|
-
<
|
21
|
+
<h2>Request Headers</h2>
|
20
22
|
<type-placeholder details="action.headers.type.attributes" type="action.headers.type" template="standalone"></type-placeholder>
|
21
23
|
</div>
|
22
24
|
</div>
|
23
25
|
|
24
26
|
<div class="row" ng-if="action.params.type.attributes">
|
25
27
|
<div class="col-lg-12">
|
26
|
-
<
|
28
|
+
<h2>Request Parameters</h2>
|
27
29
|
<type-placeholder details="action.params.type.attributes" type="action.params.type" template="standalone"></type-placeholder>
|
28
30
|
</div>
|
29
31
|
</div>
|
30
32
|
|
31
33
|
<div class="row" ng-if="action.payload.type">
|
32
34
|
<div class="col-lg-12">
|
33
|
-
<
|
35
|
+
<h2>Request Body</h2>
|
34
36
|
<type-placeholder type="action.payload.type" template="standalone" details="action.payload.type.attributes"></type-placeholder>
|
35
37
|
</div>
|
36
38
|
</div>
|
37
39
|
|
40
|
+
<div class="row">
|
41
|
+
<div class="col-lg-12">
|
42
|
+
<h2>Request Example</h2>
|
43
|
+
<div ng-if="!action.payload.examples">
|
44
|
+
<h4>URL</h4>
|
45
|
+
<url action="action" example></url>
|
46
|
+
<div ng-if="action.headers.example">
|
47
|
+
<h4>Headers</h4>
|
48
|
+
<pre><span ng-repeat="(header, value) in action.headers.example">{{header}}: {{value}}
|
49
|
+
</span></pre>
|
50
|
+
</div>
|
51
|
+
</div>
|
52
|
+
<tabset ng-if="action.payload.examples">
|
53
|
+
<tab ng-repeat="(type, example) in action.payload.examples" heading="{{type}}">
|
54
|
+
<h4>URL</h4>
|
55
|
+
<url action="action" example></url>
|
56
|
+
<div ng-if="action.headers.example">
|
57
|
+
<h4>Headers</h4>
|
58
|
+
<pre><span ng-if="example.content_type">Content-Type: {{example.content_type}}
|
59
|
+
</span><span ng-repeat="(header, value) in action.headers.example">{{header}}: {{value}}
|
60
|
+
</span></pre>
|
61
|
+
</div>
|
62
|
+
<h4>Request body</h4>
|
63
|
+
<pre>{{ example.body }}</pre>
|
64
|
+
</tab>
|
65
|
+
</tabset>
|
66
|
+
</div>
|
67
|
+
</div>
|
68
|
+
|
38
69
|
<div class="row" ng-if="hasResponses()">
|
39
70
|
<div class="col-lg-12">
|
40
|
-
<
|
41
|
-
<div class="
|
42
|
-
<
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
<
|
47
|
-
<
|
48
|
-
<
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
<
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
+
<h2>Responses</h2>
|
72
|
+
<div class="panel panel-default" ng-repeat="response in responses">
|
73
|
+
<div class="panel-heading"><h4 class="panel-title">{{response.name}}</h4></div>
|
74
|
+
<div class="panel-body">
|
75
|
+
<div class="row">
|
76
|
+
<div class="col-md-4">
|
77
|
+
<h5>Status</h5>
|
78
|
+
<p>{{ response.status }}</p>
|
79
|
+
<div ng-if="response.examples.json">
|
80
|
+
<h5>Content-Type</h5>
|
81
|
+
<p>{{ response.examples.json.content_type }}</p>
|
82
|
+
</div>
|
83
|
+
<div ng-if="response.payload.id">
|
84
|
+
<h5>Media Type</h5>
|
85
|
+
<p><type-placeholder template="label" type="response.payload"></type-placeholder></p>
|
86
|
+
</div>
|
87
|
+
</div>
|
88
|
+
<div class="col-md-8">
|
89
|
+
<div ng-if="response.payload.examples">
|
90
|
+
<h5>Response Example</h5>
|
91
|
+
<tabset ng-if="numExamples > 1">
|
92
|
+
<tab ng-repeat="(type, example) in response.payload.examples" heading="{{type}}">
|
93
|
+
<pre>{{ example.body }}</pre>
|
94
|
+
</tab>
|
95
|
+
</tabset>
|
96
|
+
<div ng-if="response.numExamples == 1">
|
97
|
+
<pre ng-repeat="(type, example) in response.payload.examples">{{ example.body }}</pre>
|
98
|
+
</div>
|
99
|
+
</div>
|
100
|
+
</div>
|
101
|
+
</div>
|
102
|
+
</div>
|
71
103
|
</div>
|
72
104
|
</div>
|
73
105
|
</div>
|
74
106
|
</div>
|
75
|
-
<hr class="action-divider" />
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<div class="row">
|
2
|
+
<div class="col-lg-12">
|
3
|
+
<h1 class="page-header">FieldSelector</h1>
|
4
|
+
|
5
|
+
<p>Field Selectors allow you to specify in a request exactly what data you
|
6
|
+
wish to recieve in the response. This allows the client to get an efficient
|
7
|
+
response with only the fields required.</p>
|
8
|
+
<p>The fields can come from the endpointʼs associated Schema, or from an
|
9
|
+
attribute exposed in any of the views of the resource. Multiple fields are
|
10
|
+
separated by commas.</p>
|
11
|
+
<p>You can also select properties from nested schemas from parent schema
|
12
|
+
using curly braces. For example <code>title,user{name,email}</code> would lead to a
|
13
|
+
response like this:</p>
|
14
|
+
<pre>{
|
15
|
+
"title": "Nice Blog Post",
|
16
|
+
"user": {
|
17
|
+
"name": "John Appleseed",
|
18
|
+
"email": "john@example.com"
|
19
|
+
}
|
20
|
+
}</pre>
|
21
|
+
<p>If you do not specify attributes of nested properties, the <code>default</code>
|
22
|
+
view will be used to render them.</p>
|
23
|
+
</div>
|
24
|
+
</div>
|
@@ -7,7 +7,13 @@
|
|
7
7
|
<h1 class="page-header">
|
8
8
|
{{ controller.name | resourceName }}
|
9
9
|
</h1>
|
10
|
-
|
10
|
+
|
11
|
+
<p ng-bind-html="controller.description | markdown"></p>
|
12
|
+
|
13
|
+
<p class="traits" ng-if="controller.traits.length > 0">
|
14
|
+
This resource is
|
15
|
+
<readable-list repeat="trait in controller.traits"><a ui-sref="root.trait({version: apiVersion, trait: trait})">{{trait}}</a></readable-list>.
|
16
|
+
</p>
|
11
17
|
</div>
|
12
18
|
</div>
|
13
19
|
<div class="row" ng-if="controller.actions.length">
|
@@ -25,13 +31,10 @@
|
|
25
31
|
<tbody>
|
26
32
|
<tr ng-repeat="action in controller.actions">
|
27
33
|
<td>
|
28
|
-
<a ui-sref="root.
|
34
|
+
<a ui-sref="root.action({action: action.name, controller: controllerName, version: apiVersion})">{{ action.name }}</a>
|
29
35
|
</td>
|
30
36
|
<td>
|
31
|
-
<
|
32
|
-
<div class="label label-default verb" ng-class="url.verb | lowercase">{{ url.verb }}</div>
|
33
|
-
<strong>{{ url.path }}</strong>
|
34
|
-
</div>
|
37
|
+
<url action="action"></url>
|
35
38
|
</td>
|
36
39
|
<td style="font-size: 110%;">
|
37
40
|
<p ng-bind-html="action.description | markdown"></p>
|
@@ -49,8 +52,4 @@
|
|
49
52
|
<h2>Schema</h2>
|
50
53
|
<p ><b>Internet Media-type: {{ controller.media_type.identifier }}</b></p>
|
51
54
|
</div>
|
52
|
-
<h1>Actions</h1>
|
53
|
-
<div ng-controller="ActionCtrl" ng-repeat="action in controller.actions">
|
54
|
-
<div id="action-{{action.name}}" ng-include="'views/action.html'"></div>
|
55
|
-
</div>
|
56
55
|
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div class="menu-item" ng-if="shouldShow">
|
2
|
+
<a href="{{link.stateRef}}"
|
3
|
+
ng-class="{active: isActive, 'child-resource': link.parent, 'action': link.isAction, 'main': !link.isAction}">
|
4
|
+
{{ link.name }}
|
5
|
+
</a>
|
6
|
+
<menu-item ng-repeat="action in link.actions" link="action"></menu-item>
|
7
|
+
<menu-item ng-repeat="resource in link.childResources" link="resource"></menu-item>
|
8
|
+
</div>
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
<div class="container" ng-cloak>
|
4
4
|
<div class="row">
|
5
|
-
<div class="col-sm-3" ng-controller="MenuCtrl" ng-include="'views/menu.html'"></div>
|
6
|
-
<div class="col-sm-9" ui-view=""></div>
|
5
|
+
<div class="col-sm-4 col-md-3" ng-controller="MenuCtrl" ng-include="'views/menu.html'"></div>
|
6
|
+
<div class="col-sm-8 col-md-9" ui-view="" autoscroll="true"></div>
|
7
7
|
</div>
|
8
8
|
</div>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<button type="button" class="btn btn-success" dropdown-toggle ng-disabled="disabled">
|
7
7
|
{{:: versionLabel}}: {{selectedVersion}} <span class="caret"></span>
|
8
8
|
</button>
|
9
|
-
<ul class="dropdown-menu
|
9
|
+
<ul class="dropdown-menu" role="menu">
|
10
10
|
<li ng-repeat="version in versions">
|
11
11
|
<a ng-click="select(version)" dropdown-toggle>{{version}}</a>
|
12
12
|
</li>
|
@@ -23,23 +23,17 @@
|
|
23
23
|
<tabset justified="true" class="tab-list-group">
|
24
24
|
<tab heading="Resources" active="active.resources">
|
25
25
|
<div class="list-group">
|
26
|
-
<
|
27
|
-
href="{{link.stateRef}}"
|
28
|
-
class="list-group-item"
|
29
|
-
ng-hide="expandChildren && link.parent && selectedGrandfatherType != link.grandfather"
|
30
|
-
ng-class="{active: link.typeName == currentType, 'child-resource': link.parent, 'group-selected': selectedGrandfatherType == link.grandfather}">
|
31
|
-
{{ link.name }}
|
32
|
-
</a>
|
26
|
+
<menu-item ng-repeat="link in availableResources() | orderBy: 'name'" link="link" toplevel="true"></menu-item>
|
33
27
|
</div>
|
34
28
|
</tab>
|
35
29
|
<tab heading="Schemas" active="active.schemas">
|
36
30
|
<div class="list-group">
|
37
|
-
<
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
31
|
+
<menu-item ng-repeat="link in availableSchemas() | orderBy: 'name'" link="link" toplevel="true"></menu-item>
|
32
|
+
</div>
|
33
|
+
</tab>
|
34
|
+
<tab heading="Traits" active="active.traits" ng-if="availableTraits().length > 0">
|
35
|
+
<div class="list-group">
|
36
|
+
<menu-item ng-repeat="link in availableTraits() | orderBy: 'name'" link="link" toplevel="true"></menu-item>
|
43
37
|
</div>
|
44
38
|
</tab>
|
45
39
|
</tabset>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<div ng-if="error" class="alert alert-danger">
|
2
|
+
<p>The requested trait could not be found.</p>
|
3
|
+
</div>
|
4
|
+
<div ng-if="trait">
|
5
|
+
<div class="row">
|
6
|
+
<div class="col-lg-12">
|
7
|
+
<h1>
|
8
|
+
{{ traitName | resourceName }}
|
9
|
+
</h1>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
<div ng-if="trait.description" ng-bind-html="trait.description | markdown"></div>
|
13
|
+
</div>
|