conjur-asset-ui 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.jshintrc +41 -0
- data/Gemfile +3 -1
- data/README.md +34 -0
- data/Rakefile +69 -1
- data/bower.json +93 -0
- data/conjur-asset-ui.gemspec +1 -1
- data/features/navigation_bar.feature +31 -0
- data/features/step_definitions/custom_step.rb +32 -0
- data/features/support/env.rb +38 -0
- data/features/support/hooks.rb +30 -0
- data/features/support/world.rb +17 -0
- data/gulpfile.js +140 -0
- data/lib/conjur/command/ui.rb +1 -1
- data/lib/conjur/webserver/server.rb +14 -9
- data/lib/conjur-asset-ui-version.rb +1 -1
- data/package.json +47 -0
- data/preprocessor.js +7 -0
- data/public/_client_libs.html +2 -15
- data/public/css/styles.less +170 -4
- data/public/index.html.erb +5 -7
- data/public/js/init.js +183 -97
- data/public/js/lib/sorted-set.no-require.js +3 -28
- data/public/js/models/groupRecord.js +12 -11
- data/public/js/models/hostRecord.js +6 -7
- data/public/js/models/layerRecord.js +12 -11
- data/public/js/models/namespace.js +2 -0
- data/public/js/models/policyList.js +3 -1
- data/public/js/models/policyRecord.js +6 -7
- data/public/js/models/record.js +24 -23
- data/public/js/models/resourceList.js +28 -10
- data/public/js/models/userList.js +7 -2
- data/public/js/models/userRecord.js +7 -8
- data/public/js/models/variableList.js +18 -7
- data/public/js/models/variableRecord.js +13 -12
- data/public/js/routers.js +72 -26
- data/public/js/views/annotations.js +38 -27
- data/public/js/views/audit.js +23 -17
- data/public/js/views/chart.js +471 -0
- data/public/js/views/dashboard.js +94 -58
- data/public/js/views/generic.js +16 -9
- data/public/js/views/group.js +94 -55
- data/public/js/views/groups.js +3 -7
- data/public/js/views/host.js +75 -44
- data/public/js/views/hosts.js +2 -6
- data/public/js/views/layer.js +127 -82
- data/public/js/views/layers.js +2 -6
- data/public/js/views/mixins/search.js +12 -5
- data/public/js/views/mixins/tabs.js +95 -55
- data/public/js/views/navSearch.js +16 -5
- data/public/js/views/owned.js +14 -8
- data/public/js/views/permissions.js +244 -178
- data/public/js/views/policies.js +2 -4
- data/public/js/views/policy.js +65 -38
- data/public/js/views/resource.js +49 -34
- data/public/js/views/role.js +52 -37
- data/public/js/views/searchResults.js +205 -138
- data/public/js/views/time.js +26 -13
- data/public/js/views/user.js +178 -55
- data/public/js/views/users.js +2 -7
- data/public/js/views/variable.js +226 -45
- data/public/js/views/variables.js +4 -8
- metadata +20 -20
- data/public/_client_code.html +0 -42
- data/public/css/bootstrap.css +0 -7
- data/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/public/fonts/glyphicons-halflings-regular.svg +0 -229
- data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/public/js/lib/JSXTransformer.js +0 -10862
- data/public/js/lib/async.js +0 -958
- data/public/js/lib/backbone.js +0 -2
- data/public/js/lib/bootstrap.js +0 -6
- data/public/js/lib/less.js +0 -16
- data/public/js/lib/moment.js +0 -7768
- data/public/js/lib/react-bootstrap.js +0 -5346
- data/public/js/lib/react-bootstrap.min.js +0 -4
- data/public/js/lib/underscore-min.js +0 -6
- data/public/js/lib/underscore.string.min.js +0 -1
- data/public/js/main.js +0 -57
data/public/js/views/role.js
CHANGED
@@ -1,41 +1,56 @@
|
|
1
1
|
/** @jsx React.DOM */
|
2
|
+
/* global conjur, React, _ */
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
}
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
}
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
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
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
+
);
|
data/public/js/views/time.js
CHANGED
@@ -1,14 +1,27 @@
|
|
1
1
|
/** @jsx React.DOM */
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
+
);
|