conjur-asset-ui-beta 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/.git-hooks/pre_commit/trailing_whitespace.rb +26 -0
  3. data/.gitignore +23 -0
  4. data/.project +18 -0
  5. data/CHANGELOG.md +14 -0
  6. data/Gemfile +10 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +72 -0
  9. data/Rakefile +76 -0
  10. data/TODO.md +31 -0
  11. data/app/.csscomb.json +304 -0
  12. data/app/.jshintrc +46 -0
  13. data/app/build/css/bootstrap.css +6906 -0
  14. data/app/build/fonts/glyphicons-halflings-regular.eot +0 -0
  15. data/app/build/fonts/glyphicons-halflings-regular.svg +288 -0
  16. data/app/build/fonts/glyphicons-halflings-regular.ttf +0 -0
  17. data/app/build/fonts/glyphicons-halflings-regular.woff +0 -0
  18. data/app/build/fonts/glyphicons-halflings-regular.woff2 +0 -0
  19. data/app/build/images/conjur-logo.svg +26 -0
  20. data/app/build/images/icon-client-pc.svg +12 -0
  21. data/app/build/images/icon-environment.png +0 -0
  22. data/app/build/images/icon-person.svg +12 -0
  23. data/app/build/images/icon-policy.png +0 -0
  24. data/app/build/images/icon-resource.png +0 -0
  25. data/app/build/images/icon-service-dots.svg +13 -0
  26. data/app/build/images/icon-variable.png +0 -0
  27. data/app/build/index.html +26 -0
  28. data/app/build/js/app.js +78070 -0
  29. data/app/build/js/pace.js +2 -0
  30. data/app/config/preprocessor.js +9 -0
  31. data/app/config/webpack.js +84 -0
  32. data/app/gulpfile.js +144 -0
  33. data/app/package.json +83 -0
  34. data/app/src/actions.js +493 -0
  35. data/app/src/app.js +76 -0
  36. data/app/src/clients/audit.js +54 -0
  37. data/app/src/clients/generic.js +87 -0
  38. data/app/src/clients/layer_members.js +36 -0
  39. data/app/src/clients/list.js +82 -0
  40. data/app/src/clients/members.js +37 -0
  41. data/app/src/clients/search.js +19 -0
  42. data/app/src/components/app/__tests__/app-test.js +22 -0
  43. data/app/src/components/app/app.js +66 -0
  44. data/app/src/components/audit/__tests__/table_header-test.js +40 -0
  45. data/app/src/components/audit/box.js +11 -0
  46. data/app/src/components/audit/constants.js +7 -0
  47. data/app/src/components/audit/entry.js +107 -0
  48. data/app/src/components/audit/fields_mixin.js +13 -0
  49. data/app/src/components/audit/humanize_event.js +216 -0
  50. data/app/src/components/audit/table.js +100 -0
  51. data/app/src/components/audit/table_header.js +38 -0
  52. data/app/src/components/audit/timestamp.js +30 -0
  53. data/app/src/components/chart/chart.js +539 -0
  54. data/app/src/components/chart/chart_helper_mixin.js +79 -0
  55. data/app/src/components/custom/list.js +5 -0
  56. data/app/src/components/custom/view.js +71 -0
  57. data/app/src/components/dashboard/activity.js +113 -0
  58. data/app/src/components/dashboard/dashboard.js +47 -0
  59. data/app/src/components/flash/flash.js +17 -0
  60. data/app/src/components/generic/__tests__/time-test.js +43 -0
  61. data/app/src/components/generic/annotations.js +41 -0
  62. data/app/src/components/generic/breadcrumbs.js +59 -0
  63. data/app/src/components/generic/foldable_audit_section.js +252 -0
  64. data/app/src/components/generic/list.js +144 -0
  65. data/app/src/components/generic/list_factory.js +42 -0
  66. data/app/src/components/generic/resource_link.js +65 -0
  67. data/app/src/components/generic/role_link.js +65 -0
  68. data/app/src/components/generic/tab_mixin.js +148 -0
  69. data/app/src/components/generic/time.js +34 -0
  70. data/app/src/components/group/list.js +5 -0
  71. data/app/src/components/group/view.js +137 -0
  72. data/app/src/components/host/activity.js +93 -0
  73. data/app/src/components/host/details.js +30 -0
  74. data/app/src/components/host/host_link.js +20 -0
  75. data/app/src/components/host/list.js +5 -0
  76. data/app/src/components/host/view.js +113 -0
  77. data/app/src/components/layer/list.js +5 -0
  78. data/app/src/components/layer/view.js +180 -0
  79. data/app/src/components/navbar/__tests__/navbar-test.js +21 -0
  80. data/app/src/components/navbar/nav_search_form.js +41 -0
  81. data/app/src/components/navbar/navbar.js +71 -0
  82. data/app/src/components/owned_resources/owned_resources.js +86 -0
  83. data/app/src/components/owned_resources/owned_resources_box.js +106 -0
  84. data/app/src/components/permissions/permissions.js +143 -0
  85. data/app/src/components/permissions/permissions_table.js +104 -0
  86. data/app/src/components/policy/list.js +5 -0
  87. data/app/src/components/policy/view.js +98 -0
  88. data/app/src/components/refresh/refresh.js +30 -0
  89. data/app/src/components/refresh/refresh.less +15 -0
  90. data/app/src/components/search/group.js +45 -0
  91. data/app/src/components/search/group_heading.js +50 -0
  92. data/app/src/components/search/group_title.js +38 -0
  93. data/app/src/components/search/result_item.js +57 -0
  94. data/app/src/components/search/search.js +103 -0
  95. data/app/src/components/user/activity.js +92 -0
  96. data/app/src/components/user/details.js +30 -0
  97. data/app/src/components/user/list.js +5 -0
  98. data/app/src/components/user/pubkeys.js +116 -0
  99. data/app/src/components/user/pubkeys.less +56 -0
  100. data/app/src/components/user/view.js +123 -0
  101. data/app/src/components/variable/activity.js +83 -0
  102. data/app/src/components/variable/details.js +48 -0
  103. data/app/src/components/variable/fetchers.js +83 -0
  104. data/app/src/components/variable/list.js +5 -0
  105. data/app/src/components/variable/updaters.js +83 -0
  106. data/app/src/components/variable/view.js +105 -0
  107. data/app/src/constants.js +35 -0
  108. data/app/src/images/conjur-logo.svg +26 -0
  109. data/app/src/images/icon-client-pc.svg +12 -0
  110. data/app/src/images/icon-environment.png +0 -0
  111. data/app/src/images/icon-person.svg +12 -0
  112. data/app/src/images/icon-policy.png +0 -0
  113. data/app/src/images/icon-resource.png +0 -0
  114. data/app/src/images/icon-service-dots.svg +13 -0
  115. data/app/src/images/icon-variable.png +0 -0
  116. data/app/src/pages/index.html +26 -0
  117. data/app/src/routes.js +57 -0
  118. data/app/src/stores/app_store.js +29 -0
  119. data/app/src/stores/audit_store.js +77 -0
  120. data/app/src/stores/group_store.js +105 -0
  121. data/app/src/stores/host_store.js +98 -0
  122. data/app/src/stores/layer_store.js +115 -0
  123. data/app/src/stores/policy_store.js +89 -0
  124. data/app/src/stores/resources_store.js +118 -0
  125. data/app/src/stores/route_store.js +24 -0
  126. data/app/src/stores/search_store.js +73 -0
  127. data/app/src/stores/user_store.js +111 -0
  128. data/app/src/stores/variable_store.js +94 -0
  129. data/app/src/styles/bootstrap.less +56 -0
  130. data/app/src/styles/styles.less +634 -0
  131. data/app/src/utils.js +43 -0
  132. data/app/src/vendor/pace.js +2 -0
  133. data/conjur-asset-ui.gemspec +36 -0
  134. data/features/navigation_bar.feature +31 -0
  135. data/features/step_definitions/custom_step.rb +32 -0
  136. data/features/support/env.rb +38 -0
  137. data/features/support/hooks.rb +30 -0
  138. data/features/support/world.rb +17 -0
  139. data/lib/conjur-asset-ui-version.rb +7 -0
  140. data/lib/conjur-asset-ui.rb +7 -0
  141. data/lib/conjur/command/ui.rb +54 -0
  142. data/lib/conjur/webserver/api_proxy.rb +94 -0
  143. data/lib/conjur/webserver/authorize.rb +28 -0
  144. data/lib/conjur/webserver/conjur_info.rb +33 -0
  145. data/lib/conjur/webserver/home.rb +42 -0
  146. data/lib/conjur/webserver/login.rb +57 -0
  147. data/lib/conjur/webserver/renderer.rb +34 -0
  148. data/lib/conjur/webserver/server.rb +130 -0
  149. data/public/js/views/roleGraph.js +91 -0
  150. metadata +373 -0
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ var RoleLink = require('../generic/role_link'),
6
+ Time = require('../generic/time'),
7
+ Refresh = require('../refresh/refresh');
8
+
9
+ module.exports = React.createClass({
10
+ displayName: 'HostDetails',
11
+
12
+ render() {
13
+ // TODO: control for 'enroll'
14
+ return (
15
+ <div className="b-host-details">
16
+ <h2>Details<Refresh show={this.props.isLoading} /></h2>
17
+ <dl className="dl-horizontal">
18
+ <dt>Owner</dt>
19
+ <dd><RoleLink id={this.props.owner}/></dd>
20
+
21
+ <dt>Created by</dt>
22
+ <dd><RoleLink id={this.props.host.userid}/></dd>
23
+
24
+ <dt>Created At</dt>
25
+ <dd><Time timestamp={this.props.host.created_at}/></dd>
26
+ </dl>
27
+ </div>
28
+ );
29
+ }
30
+ });
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ var React = require('react'),
4
+ Link = require('react-router').Link;
5
+
6
+ module.exports = React.createClass({
7
+ displayName: 'HostLink',
8
+
9
+ hostId() {
10
+ return this.props.data.split(':')[2];
11
+ },
12
+
13
+ render() {
14
+ return (
15
+ <Link to="host" params={{id: this.hostId}}>
16
+ {this.hostId()}
17
+ </Link>
18
+ );
19
+ }
20
+ });
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ var genericListFactory = require('../generic/list_factory');
4
+
5
+ module.exports = genericListFactory('host', 'Hosts');
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ var React = require('react'),
4
+ Fluxxor = require('fluxxor'),
5
+ FluxMixin = Fluxxor.FluxMixin(React),
6
+ StoreWatchMixin = Fluxxor.StoreWatchMixin,
7
+ Router = require('react-router'),
8
+ compact = require('lodash/array/compact');
9
+
10
+ var TabbedArea = require('react-bootstrap/lib/TabbedArea');
11
+
12
+ var Annotations = require('../generic/annotations'),
13
+ Breadcrumbs = require('../generic/breadcrumbs'),
14
+ FoldableAuditSection = require('../generic/foldable_audit_section'),
15
+ TabMixin = require('../generic/tab_mixin'),
16
+ Refresh = require('../refresh/refresh');
17
+
18
+ var AuditTable = require('../audit/table');
19
+
20
+ var Activity = require('./activity'),
21
+ Details = require('./details');
22
+
23
+ module.exports = React.createClass({
24
+ displayName: 'HostView',
25
+
26
+ mixins: [FluxMixin, StoreWatchMixin('audit', 'host', 'resources'), Router.State, TabMixin],
27
+
28
+ getStateFromFlux() {
29
+ var flux = this.getFlux(),
30
+ id = unescape(this.getParams().id),
31
+ audit = flux.store('audit').getEventFor('host', id),
32
+ data = flux.store('host').getData(),
33
+ resource = flux.store('resources').getResource('host', id);
34
+
35
+ var ret = {
36
+ loading: data.loading,
37
+ host: data.host,
38
+ owned: data.owned,
39
+ roles: data.roles,
40
+ owner: resource.data.owner,
41
+ annotations: resource.data.annotations,
42
+ audit: audit.data,
43
+ resources: data.resources
44
+ };
45
+
46
+ ret.loading.audit = audit.loading;
47
+ ret.loading.owner = resource.loading;
48
+ ret.loading.annotations = resource.loading;
49
+
50
+ return ret;
51
+ },
52
+
53
+ render() {
54
+ var permissionsTab = this.permissionsTab(this.state.host.roleid),
55
+ membershipsTab = this.membershipsTab(this.state.host.roleid),
56
+ ownedTab = this.ownedTab();
57
+
58
+ var tabs = compact([
59
+ membershipsTab,
60
+ ownedTab,
61
+ permissionsTab
62
+ ]);
63
+
64
+ var elems = [
65
+ {url: '/ui/hosts', text: 'Hosts'},
66
+ {url: '', text: this.state.host.id},
67
+ {url: '', text: '(owned by ' + this.state.host.ownerid + ')'}
68
+ ];
69
+
70
+ return (
71
+ <div className="b-host">
72
+ <Breadcrumbs elems={elems} />
73
+ <hr />
74
+ <Activity audit={this.state.audit}
75
+ roleid={this.state.host.roleid}
76
+ isLoading={this.state.loading.audit} />
77
+ <hr />
78
+ {FoldableAuditSection.warnings(this.state.audit, this.state.loading.audit)}
79
+ <hr />
80
+ <div className="row">
81
+ <div className="col-md-6">
82
+ <Details owner={this.state.owner}
83
+ host={this.state.host}
84
+ isLoading={this.state.loading.owner || this.state.loading.host} />
85
+ </div>
86
+ <div className="col-md-6">
87
+ <h2>Annotations<Refresh show={false} /></h2>
88
+ <Annotations annotations={this.state.annotations} />
89
+ </div>
90
+ </div>
91
+ <hr/>
92
+ <h2>Other<Refresh show={this.state.loading.annotations} /></h2>
93
+ <TabbedArea>
94
+ {tabs}
95
+ </TabbedArea>
96
+ <hr />
97
+ <AuditTable events={this.state.audit}
98
+ isLoading={this.state.loading.audit}
99
+ caption="Recent Activity" />
100
+ </div>
101
+ );
102
+ },
103
+
104
+ componentDidMount() {
105
+ var actions = this.getFlux().actions,
106
+ id = unescape(this.getParams().id);
107
+
108
+ actions.audit.loadForRole('host', id);
109
+ actions.audit.loadForResource('host', id);
110
+ actions.host.load(id);
111
+ actions.resources.loadOne('host', id);
112
+ }
113
+ });
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ var genericListFactory = require('../generic/list_factory');
4
+
5
+ module.exports = genericListFactory('layer', 'Layers');
@@ -0,0 +1,180 @@
1
+ 'use strict';
2
+
3
+ var React = require('react'),
4
+ Fluxxor = require('fluxxor'),
5
+ FluxMixin = Fluxxor.FluxMixin(React),
6
+ StoreWatchMixin = Fluxxor.StoreWatchMixin,
7
+ Router = require('react-router'),
8
+ compact = require('lodash/array/compact');
9
+
10
+ var TabbedArea = require('react-bootstrap/lib/TabbedArea'),
11
+ TabPane = require('react-bootstrap/lib/TabPane');
12
+
13
+ var AuditTable = require('../audit/table'),
14
+ Breadcrumbs = require('../generic/breadcrumbs'),
15
+ RoleLink = require('../generic/role_link'),
16
+ TabMixin = require('../generic/tab_mixin'),
17
+ HostLink = require('../host/host_link'),
18
+ utils = require('../../utils');
19
+
20
+ var abstractRole = function(expected) {
21
+ return function(role) {
22
+ var tokens = role.split(':'),
23
+ kind = tokens[1],
24
+ abstractKinds = ['@', 'layer'],
25
+ isAbstract = abstractKinds.indexOf(kind) !== -1;
26
+
27
+ return isAbstract === expected;
28
+ };
29
+ };
30
+
31
+ module.exports = React.createClass({
32
+ displayName: 'LayerView',
33
+
34
+ mixins: [FluxMixin, StoreWatchMixin('audit', 'layer', 'resources'), Router.State, TabMixin],
35
+
36
+ getStateFromFlux() {
37
+ var flux = this.getFlux(),
38
+ id = unescape(this.getParams().id),
39
+ audit = flux.store('audit').getEventFor('layer', id),
40
+ data = flux.store('layer').getData(),
41
+ resource = flux.store('resources').getResource('layer', id);
42
+
43
+ var ret = {
44
+ loading: data.loading,
45
+ layer: data.layer,
46
+ owned: data.owned,
47
+ roles: data.roles,
48
+ owner: resource.data.owner,
49
+ annotations: resource.data.annotations,
50
+ users: data.users,
51
+ admins: data.admins,
52
+ resources: data.resources,
53
+ audit: audit.data
54
+ };
55
+
56
+ ret.loading.audit = audit.loading;
57
+ ret.loading.owner = resource.loading;
58
+ ret.loading.annotations = resource.loading;
59
+
60
+ return ret;
61
+ },
62
+
63
+ render() {
64
+ var hosts = this.state.layer.hosts.map(function(host) {
65
+ return (
66
+ <li className="list-group-item list-group-item-noborder">
67
+ <HostLink data={host} />
68
+ </li>
69
+ );
70
+ });
71
+
72
+ var admins = this.state.admins.filter(abstractRole(false)).map(function(role) {
73
+ return (
74
+ <li className="list-group-item list-group-item-noborder">
75
+ <RoleLink id={role}/>
76
+ </li>
77
+ );
78
+ });
79
+
80
+ var users = this.state.users.filter(abstractRole(false)).map(function(role) {
81
+ return (
82
+ <li className="list-group-item list-group-item-noborder">
83
+ <RoleLink id={role}/>
84
+ </li>
85
+ );
86
+ });
87
+
88
+ // TODO: controls to add/remove admins/users/hosts
89
+ var overviewTab = (
90
+ <TabPane eventKey="overview" tab="Overview">
91
+ <dl className="dl-horizontal">
92
+ <dt>Owner</dt>
93
+ <dd><RoleLink id={this.state.owner} /></dd>
94
+
95
+ <dt>Created by</dt>
96
+ <dd><RoleLink id={this.state.layer.userid} /></dd>
97
+ </dl>
98
+ </TabPane>
99
+ );
100
+
101
+ var adminsTab = (
102
+ <TabPane eventKey="admins" tab={utils.getTabname('Admins', admins)}>
103
+ <ul className="list-group">
104
+ {admins}
105
+ </ul>
106
+ </TabPane>
107
+ );
108
+
109
+ var usersTab = (
110
+ <TabPane eventKey="users" tab={utils.getTabname('Users', users)}>
111
+ <ul className="list-group">
112
+ {users}
113
+ </ul>
114
+ </TabPane>
115
+ );
116
+
117
+ var hostsTab = (
118
+ <TabPane eventKey="hosts" tab={utils.getTabname('Hosts', hosts)}>
119
+ <ul className="list-group">
120
+ {hosts}
121
+ </ul>
122
+ </TabPane>
123
+ );
124
+
125
+ var auditTab = (
126
+ <TabPane eventKey="audit" tab="Recent Activity">
127
+ <div className="audit auditGroup">
128
+ <AuditTable events={this.state.audit}
129
+ caption=""
130
+ isLoading={this.state.loading.audit} />
131
+ </div>
132
+ </TabPane>
133
+ );
134
+
135
+
136
+ var permissionsTab = this.permissionsTab(this.state.layer.roleid),
137
+ membershipsTab = this.membershipsTab(this.state.layer.roleid),
138
+ annotationsTab = this.annotationsTab(),
139
+ ownedTab = this.ownedTab();
140
+
141
+ var tabs = compact([
142
+ overviewTab,
143
+ adminsTab,
144
+ usersTab,
145
+ hostsTab,
146
+ ownedTab,
147
+ membershipsTab,
148
+ permissionsTab,
149
+ annotationsTab,
150
+ auditTab
151
+ ]);
152
+
153
+ var elems = [
154
+ {url: '/ui/layers', text: 'Layers'},
155
+ {url: '', text: this.state.layer.id},
156
+ {url: '', text: '(owned by ' + this.state.layer.ownerid + ')'}
157
+ ];
158
+
159
+ return (
160
+ <div className="b-layer">
161
+ <Breadcrumbs elems={elems} />
162
+ <hr />
163
+ <h2>Layer {this.state.layer.id}</h2>
164
+ <TabbedArea defaultActiveKey="overview">
165
+ {tabs}
166
+ </TabbedArea>
167
+ </div>
168
+ );
169
+ },
170
+
171
+ componentDidMount() {
172
+ var actions = this.getFlux().actions,
173
+ id = unescape(this.getParams().id);
174
+
175
+ actions.audit.loadForRole('layer', id);
176
+ actions.audit.loadForResource('layer', id);
177
+ actions.layer.load(id);
178
+ actions.resources.loadOne('layer', id);
179
+ }
180
+ });
@@ -0,0 +1,21 @@
1
+ /* global jest, describe, it, expect */
2
+
3
+ 'use strict';
4
+
5
+ jest.dontMock('../navbar');
6
+
7
+ var React = require('react/addons'),
8
+ TestUtils = React.addons.TestUtils,
9
+ Navbar = require('../navbar');
10
+
11
+ describe('app', () => {
12
+ it('default render', () => {
13
+ var component = TestUtils.renderIntoDocument(
14
+ <Navbar userId="userId" />
15
+ );
16
+
17
+ var element = TestUtils.findRenderedDOMComponentWithClass(component, 'container');
18
+
19
+ expect(element.getDOMNode()).toBe(true);
20
+ });
21
+ });
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ var React = require('react'),
4
+ Fluxxor = require('fluxxor'),
5
+ FluxMixin = Fluxxor.FluxMixin(React);
6
+
7
+ module.exports = React.createClass({
8
+ displayName: 'NavSearchForm',
9
+
10
+ mixins: [FluxMixin],
11
+
12
+ render() {
13
+ return (
14
+ <form className="form-inline navbar-form"
15
+ role="search"
16
+ onSubmit={this.handleSubmit}>
17
+ <div className="form-group">
18
+ <input ref="input"
19
+ type="text"
20
+ className="form-control"
21
+ placeholder="Search Conjur"></input>
22
+ </div>
23
+ <button type="submit"
24
+ className="btn btn-default search-button">
25
+ Search
26
+ </button>
27
+ </form>
28
+ );
29
+ },
30
+
31
+ handleSubmit() {
32
+ var search = this.refs.input.getDOMNode().value;
33
+
34
+ if (search && search.length !== 0) {
35
+ this.getFlux().actions.routes
36
+ .transition('search', {'query': window.encodeURIComponent(search)});
37
+ }
38
+
39
+ return false;
40
+ }
41
+ });
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ var DropdownButton = require('react-bootstrap/lib/DropdownButton'),
6
+ Navbar = require('react-bootstrap/lib/Navbar'),
7
+ Nav = require('react-bootstrap/lib/Nav'),
8
+ MenuItem = require('react-bootstrap/lib/MenuItem');
9
+
10
+ var NavItemLink = require('react-router-bootstrap/lib/NavItemLink'),
11
+ MenuItemLink = require('react-router-bootstrap/lib/MenuItemLink');
12
+
13
+ var NavSearchForm = require('./nav_search_form'),
14
+ RoleLink = require('../generic/role_link');
15
+
16
+ module.exports = React.createClass({
17
+ displayName: 'Navbar',
18
+
19
+ render() {
20
+ var style = {
21
+ backgroundPositionY: '0.8em'
22
+ };
23
+
24
+ var listStyle = {
25
+ marginRight: '15px'
26
+ };
27
+
28
+ return (
29
+ <Navbar brand="Conjur">
30
+ <Nav eventKey={0}>
31
+ <NavItemLink to="dashboard">
32
+ Dashboard
33
+ </NavItemLink>
34
+ <DropdownButton eventKey={3} title="Directory">
35
+ <MenuItemLink to="users">
36
+ Users
37
+ </MenuItemLink>
38
+ <MenuItemLink to="groups">
39
+ Groups
40
+ </MenuItemLink>
41
+ <MenuItem divider />
42
+ <MenuItemLink to="hosts">
43
+ Hosts
44
+ </MenuItemLink>
45
+ <MenuItemLink to="layers">
46
+ Layers
47
+ </MenuItemLink>
48
+ <MenuItem divider />
49
+ <MenuItemLink to="variables">
50
+ Variables
51
+ </MenuItemLink>
52
+ <MenuItemLink to="custom-types">
53
+ Custom Types
54
+ </MenuItemLink>
55
+ </DropdownButton>
56
+ <NavItemLink to="policies">
57
+ Policies
58
+ </NavItemLink>
59
+ </Nav>
60
+ <Nav right eventKey={1} style={listStyle}>
61
+ <li>
62
+ <RoleLink id={this.props.userId} style={style} />
63
+ </li>
64
+ <li>
65
+ <NavSearchForm />
66
+ </li>
67
+ </Nav>
68
+ </Navbar>
69
+ );
70
+ }
71
+ });