conjur-asset-ui 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.jshintrc +41 -0
  4. data/Gemfile +3 -1
  5. data/README.md +34 -0
  6. data/Rakefile +69 -1
  7. data/bower.json +93 -0
  8. data/conjur-asset-ui.gemspec +1 -1
  9. data/features/navigation_bar.feature +31 -0
  10. data/features/step_definitions/custom_step.rb +32 -0
  11. data/features/support/env.rb +38 -0
  12. data/features/support/hooks.rb +30 -0
  13. data/features/support/world.rb +17 -0
  14. data/gulpfile.js +140 -0
  15. data/lib/conjur/command/ui.rb +1 -1
  16. data/lib/conjur/webserver/server.rb +14 -9
  17. data/lib/conjur-asset-ui-version.rb +1 -1
  18. data/package.json +47 -0
  19. data/preprocessor.js +7 -0
  20. data/public/_client_libs.html +2 -15
  21. data/public/css/styles.less +170 -4
  22. data/public/index.html.erb +5 -7
  23. data/public/js/init.js +183 -97
  24. data/public/js/lib/sorted-set.no-require.js +3 -28
  25. data/public/js/models/groupRecord.js +12 -11
  26. data/public/js/models/hostRecord.js +6 -7
  27. data/public/js/models/layerRecord.js +12 -11
  28. data/public/js/models/namespace.js +2 -0
  29. data/public/js/models/policyList.js +3 -1
  30. data/public/js/models/policyRecord.js +6 -7
  31. data/public/js/models/record.js +24 -23
  32. data/public/js/models/resourceList.js +28 -10
  33. data/public/js/models/userList.js +7 -2
  34. data/public/js/models/userRecord.js +7 -8
  35. data/public/js/models/variableList.js +18 -7
  36. data/public/js/models/variableRecord.js +13 -12
  37. data/public/js/routers.js +72 -26
  38. data/public/js/views/annotations.js +38 -27
  39. data/public/js/views/audit.js +23 -17
  40. data/public/js/views/chart.js +471 -0
  41. data/public/js/views/dashboard.js +94 -58
  42. data/public/js/views/generic.js +16 -9
  43. data/public/js/views/group.js +94 -55
  44. data/public/js/views/groups.js +3 -7
  45. data/public/js/views/host.js +75 -44
  46. data/public/js/views/hosts.js +2 -6
  47. data/public/js/views/layer.js +127 -82
  48. data/public/js/views/layers.js +2 -6
  49. data/public/js/views/mixins/search.js +12 -5
  50. data/public/js/views/mixins/tabs.js +95 -55
  51. data/public/js/views/navSearch.js +16 -5
  52. data/public/js/views/owned.js +14 -8
  53. data/public/js/views/permissions.js +244 -178
  54. data/public/js/views/policies.js +2 -4
  55. data/public/js/views/policy.js +65 -38
  56. data/public/js/views/resource.js +49 -34
  57. data/public/js/views/role.js +52 -37
  58. data/public/js/views/searchResults.js +205 -138
  59. data/public/js/views/time.js +26 -13
  60. data/public/js/views/user.js +178 -55
  61. data/public/js/views/users.js +2 -7
  62. data/public/js/views/variable.js +226 -45
  63. data/public/js/views/variables.js +4 -8
  64. metadata +20 -20
  65. data/public/_client_code.html +0 -42
  66. data/public/css/bootstrap.css +0 -7
  67. data/public/fonts/glyphicons-halflings-regular.eot +0 -0
  68. data/public/fonts/glyphicons-halflings-regular.svg +0 -229
  69. data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  70. data/public/fonts/glyphicons-halflings-regular.woff +0 -0
  71. data/public/js/lib/JSXTransformer.js +0 -10862
  72. data/public/js/lib/async.js +0 -958
  73. data/public/js/lib/backbone.js +0 -2
  74. data/public/js/lib/bootstrap.js +0 -6
  75. data/public/js/lib/less.js +0 -16
  76. data/public/js/lib/moment.js +0 -7768
  77. data/public/js/lib/react-bootstrap.js +0 -5346
  78. data/public/js/lib/react-bootstrap.min.js +0 -4
  79. data/public/js/lib/underscore-min.js +0 -6
  80. data/public/js/lib/underscore.string.min.js +0 -1
  81. data/public/js/main.js +0 -57
@@ -1,41 +1,56 @@
1
1
  /** @jsx React.DOM */
2
+ /* global conjur, React, _ */
2
3
 
3
- /** render a link to the role represented by this.props.id
4
- Example: <RoleLink id="ci:user:jon"/>
5
- */
6
- var RoleLink = React.createClass({
7
- render: function() {
8
- var tokens = this.props.id.split(":");
9
- var kind = tokens[1];
10
- var id = tokens[tokens.length-1];
11
- if (tokens.length==1) { // just username
12
- kind="user";
13
- id=tokens[0];
14
- }
15
-
16
- // TODO: shouldn't point to unknown types
17
- var href = "/ui/" + conjur.utils.pluralize(kind) + "/" + encodeURIComponent(id);
18
- var classes = ["role-link"];
19
-
20
- var known_types=['user','group','layer','host','policy'];
21
- var kind_is_known = _.contains(known_types, kind);
22
- var text = id;
23
-
24
- if( !this.props.noIcon ) {
25
- if (kind_is_known) {
26
- classes.push(kind);
27
- } else {
28
- classes.push('abstract'); // we have no picture for abstract role yet
29
- if (text==id) {
30
- text=[kind,text].join(":"); // prepend kind to id
4
+ (function(conjur, React, _) {
5
+ 'use strict';
6
+
7
+ /** render a link to the role represented by this.props.id
8
+ Example: <RoleLink id='ci:user:jon'/>
9
+ */
10
+ this.RoleLink = React.createClass({
11
+ render: function() {
12
+ var tokens = this.props.id.split(':'),
13
+ kind = tokens[1],
14
+ id = tokens[tokens.length-1];
15
+
16
+ if (tokens.length === 1) { // just username
17
+ kind = 'user';
18
+ id = tokens[0];
31
19
  }
20
+
21
+ // TODO: shouldn't point to unknown types
22
+ var href = '/ui/' + conjur.utils.pluralize(kind) + '/' + window.encodeURIComponent(id);
23
+
24
+ var classes = ['role-link'],
25
+ knownTypes = ['user','group','layer','host','policy'],
26
+ kindIsKnown = _.contains(knownTypes, kind),
27
+ text = id;
28
+
29
+ if (!this.props.noIcon) {
30
+ if (kindIsKnown) {
31
+ classes.push(kind);
32
+ } else {
33
+ classes.push('abstract'); // we have no picture for abstract role yet
34
+
35
+ if (text === id) {
36
+ text = [kind, text].join(':'); // prepend kind to id
37
+ }
38
+ }
39
+ } else if (text === id) {
40
+ text = [kind, text].join(':'); // prepend kind to id
41
+ }
42
+
43
+ return (
44
+ <a className={classes.join(' ')} href={href}>
45
+ {text}
46
+ </a>
47
+ );
32
48
  }
33
- } else if (text==id) {
34
- text=[kind,text].join(":"); // prepend kind to id
35
- }
36
-
37
- return <a className={classes.join(' ')} href={href}>
38
- {text}
39
- </a>;
40
- }
41
- });
49
+ });
50
+
51
+ }).bind(conjur.views)
52
+ (
53
+ conjur,
54
+ React,
55
+ _
56
+ );
@@ -1,145 +1,212 @@
1
1
  /**@jsx React.DOM*/
2
+ /* global conjur, React, jQuery, _ */
2
3
 
3
- var SearchGroupTitle = React.createClass({
4
- render: function(){
5
- return <span>{this.title()}</span>
6
- },
7
-
8
- title: function(){
9
- var words = this.props.data.kind.replace(/[-_]/, ' ').split(' ');
10
- words[words.length - 1] = conjur.utils.pluralize(words[words.length - 1]);
11
- return words.map(_.str.capitalize).join(' ') + ' (' + this.props.data.items.length + ')';
12
- }
13
- });
14
-
15
- var SearchGroupHeading = React.createClass({
16
- render: function(){
17
- var targetId = "#search-collapse-" + this.props.data.kind;
18
- return <div className="panel-heading">
19
- <h4 className="panel-title">
20
- <a data-toggle="collapse" data-target={targetId}
21
- className={'group-heading' + this.props.data.kind}>
22
- <SearchGroupTitle data={this.props.data} />
23
- </a>
24
- </h4>
25
- </div>;
26
- },
27
-
28
- title: function(){
29
- var words = this.props.data.kind.replace(/[-_]/, ' ').split(' ');
30
- words[words.length - 1] = conjur.utils.pluralize(words[words.length - 1]);
31
- return words.map(_.str.capitalize).join(' ') + ' (' + this.props.data.items.length + ')';
32
- }
33
- });
34
-
35
- var SearchResultItem = React.createClass({
36
- render: function(){
37
- return <div className="item">
38
- <h4> { this.titleLink() } </h4>
39
- <div className="details">
40
- <strong> ID: </strong> <ResourceLink data={this.props.data.id} noIcon="true"/>
41
- <strong> Owner: </strong> <RoleLink id={this.props.data.owner} noIcon="true"/>
42
- </div>
43
- <div className="comment">
44
- {this.commentText()}
45
- </div>
46
- </div>;
47
- },
48
-
49
- commentText: function(){
50
- var annots = this.annotationsMap();
51
- return annots['description'] || "";
52
- },
53
-
54
- titleLink: function(){
55
- var annots = this.annotationsMap();
56
- return <ResourceLink data={this.props.data.id} text={annots['name']}/>
57
- },
58
-
59
- annotationsMap: function(){
60
- if(this._annotationsMap) return this._annotationsMap;
61
- var map = this._annotationsMap = {};
62
- (this.props.data.annotations || []).forEach(function(a){
63
- map[a.name] = a.value;
4
+
5
+ (function(conjur, React, $, _) {
6
+ 'use strict';
7
+
8
+ var ResourceLink = conjur.views.ResourceLink,
9
+ RoleLink = conjur.views.RoleLink;
10
+
11
+ var SearchGroupTitle = React.createClass({
12
+ render: function() {
13
+ return (
14
+ <span>{this.title()}</span>
15
+ );
16
+ },
17
+
18
+ title: function() {
19
+ var words = this.props.data.kind.replace(/[-_]/, ' ').split(' ');
20
+
21
+ words[words.length - 1] = conjur.utils.pluralize(words[words.length - 1]);
22
+
23
+ return (
24
+ words.map(_.str.capitalize).join(' ') + ' (' + this.props.data.items.length + ')'
25
+ );
26
+ }
64
27
  });
65
- return map;
66
- }
67
- });
68
-
69
- // accepts props like data: { kind:"", items:[] }
70
- var SearchGroup = React.createClass({
71
- render: function(){
72
- var id = "search-group-" + this.props.data.kind;
73
- var items = this.props.data.items.map(function(r){
74
- return <SearchResultItem data={r}/>
75
- })
76
- return <div id={id} className="panel panel-default search-group">
77
- <SearchGroupHeading data={this.props.data}/>
78
- <div id={"search-collapse-" + this.props.data.kind} className="panel-collapse collapse in">
79
- <div className="panel-body">
80
- {items}
81
- </div>
82
- </div>
83
- </div>;
84
- }
85
- });
86
-
87
- var SearchResults = React.createClass({
88
- render: function() {
89
- var results = this.props.data.results;
90
- var grouped = _.groupBy(results, function(r){
91
- return r.id.split(':')[1];
28
+
29
+ var SearchGroupHeading = React.createClass({
30
+ render: function() {
31
+ var targetId = '#search-collapse-' + this.props.data.kind;
32
+
33
+ return (
34
+ <div className="panel-heading">
35
+ <h4 className="panel-title">
36
+ <a data-toggle="collapse"
37
+ data-target={targetId}
38
+ className={'group-heading' + this.props.data.kind}>
39
+ <SearchGroupTitle data={this.props.data} />
40
+ </a>
41
+ </h4>
42
+ </div>
43
+ );
44
+ },
45
+
46
+ title: function() {
47
+ var words = this.props.data.kind.replace(/[-_]/, ' ').split(' ');
48
+
49
+ words[words.length - 1] = conjur.utils.pluralize(words[words.length - 1]);
50
+
51
+ return (
52
+ words.map(_.str.capitalize).join(' ') + ' (' + this.props.data.items.length + ')'
53
+ );
54
+ }
92
55
  });
93
- // Don't care about these
94
- delete grouped['environment-variables']
95
- delete grouped['notification']
96
- delete grouped['queue']
97
-
98
- var groups = _.map(grouped,function(items, key){
99
- var data = {items:items, kind: key}; // - prevent editor barfing
100
- return <SearchGroup data={data}/>
56
+
57
+ var SearchResultItem = React.createClass({
58
+ render: function() {
59
+ return (
60
+ <div className="item">
61
+ <h4>{this.titleLink()}</h4>
62
+ <div className="details">
63
+ <strong> ID: </strong> <ResourceLink data={this.props.data.id}
64
+ noIcon="true" />
65
+ <strong> Owner: </strong> <RoleLink id={this.props.data.owner}
66
+ noIcon="true" />
67
+ </div>
68
+ <div className="comment">
69
+ {this.commentText()}
70
+ </div>
71
+ </div>
72
+ );
73
+ },
74
+
75
+ commentText: function() {
76
+ var annots = this.annotationsMap();
77
+
78
+ return annots.description || '';
79
+ },
80
+
81
+ titleLink: function(){
82
+ var annots = this.annotationsMap();
83
+
84
+ return (
85
+ <ResourceLink data={this.props.data.id} text={annots.name} />
86
+ );
87
+ },
88
+
89
+ annotationsMap: function(){
90
+ if (this._annotationsMap) {
91
+ return this._annotationsMap;
92
+ }
93
+
94
+ var map = this._annotationsMap = {};
95
+
96
+ (this.props.data.annotations || []).forEach(function(a) {
97
+ map[a.name] = a.value;
98
+ });
99
+
100
+ return map;
101
+ }
101
102
  });
102
- var scores = {
103
- 'policy': 1,
104
- 'layer': 2,
105
- 'group': 3,
106
- 'host': 4,
107
- 'user': 5,
108
- 'variable': 6,
109
- 'key_pair': 7
110
- };
111
- groups.sort(function(a, b) {
112
- return ( scores[a.props.data.kind] || 100 ) - ( scores[b.props.data.kind] || 100 );
103
+
104
+ // accepts props like data: { kind:"", items:[] }
105
+ var SearchGroup = React.createClass({
106
+ render: function() {
107
+ var id = 'search-group-' + this.props.data.kind;
108
+
109
+ var items = this.props.data.items.map(function(r) {
110
+ return (
111
+ <SearchResultItem data={r}/>
112
+ );
113
+ });
114
+
115
+ return (
116
+ <div id={id} className="panel panel-default search-group">
117
+ <SearchGroupHeading data={this.props.data}/>
118
+ <div id={'search-collapse-' + this.props.data.kind}
119
+ className="panel-collapse collapse in">
120
+ <div className="panel-body">
121
+ {items}
122
+ </div>
123
+ </div>
124
+ </div>
125
+ );
126
+ }
113
127
  });
114
- var toc = groups.map(function(g) {
115
- var gid = "#search-group-" + g.props.data.kind;
116
- return <div className="toc-item">
117
- <a href={gid}><SearchGroupTitle data={g.props.data} /></a>
118
- </div>
128
+
129
+ var SearchResults = this.SearchResults = React.createClass({
130
+ render: function() {
131
+ var results = this.props.data.results;
132
+
133
+ var grouped = _.groupBy(results, function(r) {
134
+ return r.id.split(':')[1];
135
+ });
136
+
137
+ // Don't care about these
138
+ delete grouped['environment-variables'];
139
+ delete grouped.notification;
140
+ delete grouped.queue;
141
+
142
+ var groups = _.map(grouped, function(items, key) {
143
+ var data = {items: items, kind: key}; // - prevent editor barfing
144
+ return <SearchGroup data={data}/>;
145
+ });
146
+
147
+ var scores = {
148
+ 'policy': 1,
149
+ 'layer': 2,
150
+ 'group': 3,
151
+ 'host': 4,
152
+ 'user': 5,
153
+ 'variable': 6,
154
+ 'key_pair': 7
155
+ };
156
+
157
+ groups.sort(function(a, b) {
158
+ return (
159
+ (scores[a.props.data.kind] || 100) -
160
+ (scores[b.props.data.kind] || 100)
161
+ );
162
+ });
163
+
164
+ var toc = groups.map(function(g) {
165
+ var gid = '#search-group-' + g.props.data.kind;
166
+
167
+ return (
168
+ <div className="toc-item">
169
+ <a href={gid}><SearchGroupTitle data={g.props.data} /></a>
170
+ </div>
171
+ );
172
+ });
173
+
174
+ var heading = 'Found ' + this.props.data.results.length +
175
+ ' resources matching "' + this.props.data.search + '"';
176
+
177
+ return (
178
+ <div id="searchResults">
179
+ <div className="searchResults">
180
+ <h3> { heading } </h3>
181
+ <div className="search-results-toc">
182
+ {toc}
183
+ </div>
184
+ <div className="search-results">
185
+ {groups}
186
+ </div>
187
+ </div>
188
+ </div>
189
+ );
190
+ }
119
191
  });
120
- var heading = "Found " + this.props.data.results.length +
121
- " resources matching \"" + this.props.data.search + "\"";
122
- return (
123
- <div id="searchResults">
124
- <div className="searchResults">
125
- <h3> { heading } </h3>
126
- <div className="search-results-toc">
127
- {toc}
128
- </div>
129
- <div className="search-results">
130
- {groups}
131
- </div>
132
- </div>
133
- </div>
134
- );
135
- }
136
- });
137
-
138
- SearchResults.search = function(search, container){
139
- container = container || document.getElementById('content');
140
- $.get(conjur.app.endpoints.authz("resources", {search: search.replace('-',' ')}), function(results){
141
-
142
- var data = {search: search, results: results};
143
- React.renderComponent(<SearchResults data={data}/>, container);
144
- });
145
- }
192
+
193
+ SearchResults.search = function(search, container) {
194
+ container = container || document.getElementById('content');
195
+
196
+ $.get(
197
+ conjur.app.endpoints.authz('resources', {search: search.replace('-',' ')}),
198
+ function(results) {
199
+ var data = {search: search, results: results};
200
+ React.renderComponent(<SearchResults data={data}/>, container);
201
+ }
202
+ );
203
+ };
204
+
205
+
206
+ }).bind(conjur.views)
207
+ (
208
+ conjur,
209
+ React,
210
+ jQuery,
211
+ _
212
+ );
@@ -1,14 +1,27 @@
1
1
  /** @jsx React.DOM */
2
-
3
- // render a <time> tag. props.timestamp should be a timestamp
4
- // that moment can parse, props.format should be one of the
5
- // format strings accepted by moment (optional).
6
- var Time = React.createClass({
7
- render: function(){
8
- var timestamp = this.props.timestamp;
9
- var format = this.props.format || 'lll';
10
- var m = moment(timestamp);
11
-
12
- return <time dateTime={m.format()}>{m.format(format)}</time>;
13
- }
14
- })
2
+ /* global conjur, React, moment */
3
+
4
+ (function(conjur, React, moment) {
5
+ 'use strict';
6
+
7
+ // render a <time> tag. props.timestamp should be a timestamp
8
+ // that moment can parse, props.format should be one of the
9
+ // format strings accepted by moment (optional).
10
+ this.Time = React.createClass({
11
+ render: function(){
12
+ var timestamp = this.props.timestamp;
13
+ var format = this.props.format || 'lll';
14
+ var m = moment(timestamp);
15
+
16
+ return (
17
+ <time dateTime={m.format()}>{m.format(format)}</time>
18
+ );
19
+ }
20
+ });
21
+
22
+ }).bind(conjur.views)
23
+ (
24
+ conjur,
25
+ React,
26
+ moment
27
+ );