Skip to content

Commit bfb84fd

Browse files
weandReamer
authored andcommitted
extend credentials ui
1 parent 8ae73c5 commit bfb84fd

File tree

5 files changed

+175
-5
lines changed

5 files changed

+175
-5
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
angular.module('zeppelinWebApp').directive('credentialItem', CredentialItemDirective);
16+
17+
function CredentialItemDirective($timeout) {
18+
'ngInject';
19+
20+
return {
21+
restrict: 'A',
22+
link: function(scope, element, attr) {
23+
if (scope.$last === true) {
24+
$timeout(function() {
25+
let id = 'ngRenderFinished';
26+
scope.$emit(id);
27+
});
28+
}
29+
},
30+
};
31+
}

zeppelin-web/src/app/credential/credential.controller.js

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ function CredentialController($scope, $rootScope, $http, baseUrlSrv, ngToast) {
2626
$scope.entity = '';
2727
$scope.password = '';
2828
$scope.username = '';
29+
$scope.readers = [];
30+
$scope.owners = [];
2931

3032
$scope.hasCredential = () => {
3133
return Array.isArray($scope.credentialInfo) && $scope.credentialInfo.length;
@@ -35,7 +37,7 @@ function CredentialController($scope, $rootScope, $http, baseUrlSrv, ngToast) {
3537
$http.get(baseUrlSrv.getRestApiBase() + '/credential')
3638
.success(function(data, status, headers, config) {
3739
$scope.credentialInfo.length = 0; // keep the ref while cleaning
38-
const returnedCredentials = data.body.userCredentials;
40+
const returnedCredentials = data.body;
3941

4042
for (let key in returnedCredentials) {
4143
if (returnedCredentials.hasOwnProperty(key)) {
@@ -44,6 +46,8 @@ function CredentialController($scope, $rootScope, $http, baseUrlSrv, ngToast) {
4446
entity: key,
4547
password: value.password,
4648
username: value.username,
49+
readers: value.readers,
50+
owners: value.owners,
4751
});
4852
}
4953
}
@@ -75,8 +79,16 @@ function CredentialController($scope, $rootScope, $http, baseUrlSrv, ngToast) {
7579
'entity': $scope.entity,
7680
'username': $scope.username,
7781
'password': $scope.password,
82+
'owners': angular.element('#NewCredentialOwners').val(),
83+
'readers': angular.element('#NewCredentialReaders').val(),
7884
};
7985

86+
for (let i = 0; i < newCredential.owners.length; i++) {
87+
newCredential.owners[i] = newCredential.owners[i].trim();
88+
}
89+
for (let i = 0; i < newCredential.readers.length; i++) {
90+
newCredential.readers[i] = newCredential.readers[i].trim();
91+
}
8092
$http.put(baseUrlSrv.getRestApiBase() + '/credential', newCredential)
8193
.success(function(data, status, headers, config) {
8294
showToast('Successfully saved credentials.', 'success');
@@ -115,8 +127,21 @@ function CredentialController($scope, $rootScope, $http, baseUrlSrv, ngToast) {
115127
$scope.toggleAddNewCredentialInfo = function() {
116128
if ($scope.showAddNewCredentialInfo) {
117129
$scope.showAddNewCredentialInfo = false;
130+
angular.element('#NewCredentialOwners').select2({});
131+
angular.element('#NewCredentialReaders').select2({});
118132
} else {
133+
let initialOwner = $rootScope.ticket.principal === 'anonymous' ? [] : [$rootScope.ticket.principal];
119134
$scope.showAddNewCredentialInfo = true;
135+
$scope.owners = initialOwner;
136+
$scope.readers = [];
137+
angular.element('#NewCredentialOwners').select2(getSelectJson());
138+
angular.element('#NewCredentialReaders').select2(getSelectJson());
139+
if (initialOwner.length) {
140+
let initialOwnerOption = new Option(initialOwner[0], initialOwner[0], true, false);
141+
angular.element('#NewCredentialOwners').append(initialOwnerOption).trigger('change');
142+
}
143+
angular.element('#NewCredentialOwners').val(null).trigger('change');
144+
angular.element('#NewCredentialReaders').val(null).trigger('change');
120145
}
121146
};
122147

@@ -129,12 +154,19 @@ function CredentialController($scope, $rootScope, $http, baseUrlSrv, ngToast) {
129154
$scope.entity = '';
130155
$scope.username = '';
131156
$scope.password = '';
157+
$scope.readers = [];
158+
$scope.owners = [];
132159
};
133160

134161
$scope.copyOriginCredentialsInfo = function() {
135162
showToast('Since entity is a unique key, you can edit only username & password', 'info');
136163
};
137164

165+
let renderOwnersReadersSelect2 = function(entity) {
166+
angular.element('#' + entity + 'Owners').select2(getSelectJson());
167+
angular.element('#' + entity + 'Readers').select2(getSelectJson());
168+
};
169+
138170
$scope.updateCredentialInfo = function(form, data, entity) {
139171
if (!data.username || !data.password) {
140172
showToast('Username \\ Password can not be empty.', 'danger');
@@ -145,18 +177,32 @@ function CredentialController($scope, $rootScope, $http, baseUrlSrv, ngToast) {
145177
entity: entity,
146178
username: data.username,
147179
password: data.password,
180+
owners: angular.element('#' + entity + 'Owners').val(),
181+
readers: angular.element('#' + entity + 'Readers').val(),
148182
};
149183

184+
for (let i = 0; i < credential.owners.length; i++) {
185+
credential.owners[i] = credential.owners[i].trim();
186+
}
187+
for (let i = 0; i < credential.readers.length; i++) {
188+
credential.readers[i] = credential.readers[i].trim();
189+
}
150190
$http.put(baseUrlSrv.getRestApiBase() + '/credential/', credential)
151191
.success(function(data, status, headers, config) {
152192
const index = $scope.credentialInfo.findIndex((elem) => elem.entity === entity);
153193
$scope.credentialInfo[index] = credential;
194+
setTimeout(function() {
195+
renderOwnersReadersSelect2(entity);
196+
}, 100);
154197
return true;
155198
})
156199
.error(function(data, status, headers, config) {
157200
showToast('We could not save the credential', 'danger');
158201
console.log('Error %o %o', status, data.message);
159202
form.$show();
203+
setTimeout(function() {
204+
renderOwnersReadersSelect2(entity);
205+
}, 100);
160206
});
161207
return false;
162208
};
@@ -198,6 +244,68 @@ function CredentialController($scope, $rootScope, $http, baseUrlSrv, ngToast) {
198244
}
199245
}
200246

247+
let getSelectJson = function() {
248+
let selectJson = {
249+
tags: true,
250+
minimumInputLength: 3,
251+
multiple: true,
252+
tokenSeparators: [',', ' '],
253+
ajax: {
254+
url: function(params) {
255+
if (!params.term) {
256+
return false;
257+
}
258+
return baseUrlSrv.getRestApiBase() + '/security/userlist/' + params.term;
259+
},
260+
delay: 250,
261+
processResults: function(data, params) {
262+
let results = [];
263+
264+
if (data.body.users.length !== 0) {
265+
let users = [];
266+
for (let len = 0; len < data.body.users.length; len++) {
267+
users.push({
268+
'id': data.body.users[len],
269+
'text': data.body.users[len],
270+
});
271+
}
272+
results.push({
273+
'text': 'Users :',
274+
'children': users,
275+
});
276+
}
277+
if (data.body.roles.length !== 0) {
278+
let roles = [];
279+
for (let len = 0; len < data.body.roles.length; len++) {
280+
roles.push({
281+
'id': data.body.roles[len],
282+
'text': data.body.roles[len],
283+
});
284+
}
285+
results.push({
286+
'text': 'Roles :',
287+
'children': roles,
288+
});
289+
}
290+
return {
291+
results: results,
292+
pagination: {
293+
more: false,
294+
},
295+
};
296+
},
297+
cache: false,
298+
},
299+
};
300+
return selectJson;
301+
};
302+
303+
$scope.$on('ngRenderFinished', function(event, data) {
304+
for (let credential = 0; credential < $scope.credentialInfo.length; credential++) {
305+
renderOwnersReadersSelect2($scope.credentialInfo[credential].entity);
306+
}
307+
});
308+
201309
$scope.getCredentialDocsLink = function() {
202310
const currentVersion = $rootScope.zeppelinVersion;
203311
const isVersionOver0Point7 = currentVersion && currentVersion.split('.')[1] > 7;

zeppelin-web/src/app/credential/credential.html

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,29 @@ <h4>Add new credential</h4>
5656
<th style="width:30%">Entity</th>
5757
<th>Username</th>
5858
<th>Password</th>
59+
<th>Owners</th>
60+
<th>Readers</th>
5961
</tr>
6062
</thead>
6163
<tr>
6264
<td>
63-
<input id="entityname" ng-model="entity" placeholder="Interpreter Name"/>
65+
<input id="entityname" ng-model="entity" placeholder="Credential entity (e.g. Interpreter Name)"/>
6466
</td>
6567
<td>
6668
<textarea msd-elastic ng-model="username"></textarea>
6769
</td>
6870
<td>
6971
<input type="password" ng-model="password"/>
7072
</td>
73+
<td>
74+
<select id="NewCredentialOwners" class="form-control" multiple="multiple">
75+
<option ng-repeat="owner in owners" selected="selected">{{owner}}</option>
76+
</select>
77+
</td>
78+
<td>
79+
<select id="NewCredentialReaders" class="form-control" multiple="multiple">
80+
</select>
81+
</td>
7182
</tr>
7283
</table>
7384
<span class="btn btn-primary" ng-click="addNewCredentialInfo()">
@@ -90,13 +101,16 @@ <h4>Add new credential</h4>
90101
class="col-md-12 gray40-message">
91102
<em>Currently there is no credential information</em>
92103
</div>
104+
<div credential-item ng-repeat="credential in credentialInfo"></div>
93105
<div class="col-md-12" ng-show="hasCredential(credentialInfo) || valueform.$visible">
94106
<table class="table table-striped">
95107
<thead>
96108
<tr>
97109
<th style="width:30%">Entity</th>
98110
<th>Username</th>
99111
<th>Password</th>
112+
<th>Owners</th>
113+
<th>Readers</th>
100114
<th></th>
101115
</tr>
102116
</thead>
@@ -119,6 +133,16 @@ <h4>Add new credential</h4>
119133
**********
120134
</span>
121135
</td>
136+
<td>
137+
<select id="{{credential.entity}}Owners" class="form-control" multiple="multiple" ng-disabled="!valueform.$visible">
138+
<option ng-repeat="owner in credential.owners" selected="selected">{{owner}}</option>
139+
</select>
140+
</td>
141+
<td>
142+
<select id="{{credential.entity}}Readers" class="form-control" multiple="multiple" ng-disabled="!valueform.$visible">
143+
<option ng-repeat="reader in credential.readers" selected="selected">{{reader}}</option>
144+
</select>
145+
</td>
122146
<td>
123147
<!-- Edit credential info -->
124148
<span style="float:right" ng-show="!valueform.$visible">
@@ -135,7 +159,8 @@ <h4>Add new credential</h4>
135159
<form editable-form name="valueform"
136160
onbeforesave="updateCredentialInfo(valueform, $data, credential.entity)"
137161
ng-show="valueform.$visible">
138-
<button type="submit" class="btn btn-primary btn-xs">
162+
<button type="submit" class="btn btn-primary btn-xs"
163+
ng-click="resetSelect(credential.entity)">
139164
<span class="fa fa-check"></span> save
140165
</button>
141166
<button type="button" class="btn btn-default btn-xs"

zeppelin-web/src/app/credential/credential.test.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ describe('Controller: Credential', function() {
1414
$httpBackend = _$httpBackend_;
1515
}));
1616

17-
const credentialResponse = {'spark.testCredential': {username: 'user1', password: 'password1'}};
17+
const credentialResponse = {'spark.testCredential': {
18+
username: 'user1',
19+
password: 'password1',
20+
readers: [],
21+
owners: ['anonymous']},
22+
};
1823
const interpreterResponse = [
1924
{'name': 'spark', 'group': 'spark'},
2025
{'name': 'md', 'group': 'md'},
@@ -42,7 +47,7 @@ describe('Controller: Credential', function() {
4247
$httpBackend.flush();
4348

4449
expect($scope.credentialInfo).toEqual(
45-
[{entity: 'spark.testCredential', username: 'user1', password: 'password1'}]
50+
[{entity: 'spark.testCredential', username: 'user1', password: 'password1', readers: [], owners: ['anonymous']}]
4651
);
4752
expect($scope.availableInterpreters).toEqual(
4853
['spark', 'md']

zeppelin-web/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import './app/interpreter/interpreter.filter.js';
4343
import './app/interpreter/interpreter-item.directive.js';
4444
import './app/interpreter/widget/number-widget.directive.js';
4545
import './app/credential/credential.controller.js';
46+
import './app/credential/credential-item.directive.js';
4647
import './app/configuration/configuration.controller.js';
4748
import './app/notebook/revisions-comparator/revisions-comparator.component.js';
4849
import './app/notebook/paragraph/paragraph.controller.js';

0 commit comments

Comments
 (0)