mirror of
https://github.com/ansible/awx.git
synced 2026-03-18 09:27:31 -02:30
implement users tokens sub list
This commit is contained in:
@@ -136,6 +136,7 @@
|
|||||||
@import '../../src/tooltip/tooltip.block.less';
|
@import '../../src/tooltip/tooltip.block.less';
|
||||||
@import '../../src/workflow-results/workflow-status-bar/workflow-status-bar.block.less';
|
@import '../../src/workflow-results/workflow-status-bar/workflow-status-bar.block.less';
|
||||||
@import '../../src/workflow-results/workflow-results.block.less';
|
@import '../../src/workflow-results/workflow-results.block.less';
|
||||||
|
@import '../../src/users/token-modal.block.less';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export default
|
|||||||
return $http({
|
return $http({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: `/api/login/`,
|
url: `/api/login/`,
|
||||||
data: `username=${username}&password=${password}&csrfmiddlewaretoken=${csrfmiddlewaretoken}&next=%2fapi%2f`,
|
data: `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}&csrfmiddlewaretoken=${csrfmiddlewaretoken}&next=%2fapi%2f`,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,14 +166,18 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
// Also wraps mess of generated HTML in a .Panel
|
// Also wraps mess of generated HTML in a .Panel
|
||||||
wrapPanel(html, ignorePanel){
|
wrapPanel(html, ignorePanel){
|
||||||
if(ignorePanel) {
|
if(ignorePanel) {
|
||||||
return `<div>
|
return `
|
||||||
|
<div ui-view="preFormView"></div>
|
||||||
|
<div>
|
||||||
${html}
|
${html}
|
||||||
<div ui-view="related"></div>
|
<div ui-view="related"></div>
|
||||||
<div ui-view="modal"></div>
|
<div ui-view="modal"></div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return `<div class="Panel">
|
return `
|
||||||
|
<div ui-view="preFormView"></div>
|
||||||
|
<div class="Panel">
|
||||||
${html}
|
${html}
|
||||||
<div ui-view="related"></div>
|
<div ui-view="related"></div>
|
||||||
<div ui-view="modal"></div>
|
<div ui-view="modal"></div>
|
||||||
|
|||||||
@@ -583,7 +583,8 @@ export default ['$compile', 'Attr', 'Icon',
|
|||||||
},
|
},
|
||||||
|
|
||||||
wrapPanel: function(html){
|
wrapPanel: function(html){
|
||||||
return `<div class="Panel">${html}</div>`;
|
return `
|
||||||
|
<div class="Panel">${html}</div>`;
|
||||||
},
|
},
|
||||||
|
|
||||||
insertFormView: function(){
|
insertFormView: function(){
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export default ['$scope', '$rootScope', '$stateParams', 'UserForm', 'Rest',
|
|||||||
init();
|
init();
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
$scope.isCurrentlyLoggedInUser = (parseInt(id) === $rootScope.current_user.id);
|
||||||
$scope.hidePagination = false;
|
$scope.hidePagination = false;
|
||||||
$scope.hideSmartSearch = false;
|
$scope.hideSmartSearch = false;
|
||||||
$scope.user_type_options = user_type_options;
|
$scope.user_type_options = user_type_options;
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ import UsersAdd from './add/users-add.controller';
|
|||||||
import UsersEdit from './edit/users-edit.controller';
|
import UsersEdit from './edit/users-edit.controller';
|
||||||
import UserForm from './users.form';
|
import UserForm from './users.form';
|
||||||
import UserList from './users.list';
|
import UserList from './users.list';
|
||||||
|
import UserTokensListRoute from './users-tokens-list.route';
|
||||||
|
import UserTokensAddRoute from './users-tokens-add.route';
|
||||||
|
import UserTokensAddApplicationRoute from './users-tokens-add-application.route';
|
||||||
|
import TokensStrings from './tokens.strings';
|
||||||
|
|
||||||
import { N_ } from '../i18n';
|
import { N_ } from '../i18n';
|
||||||
|
|
||||||
export default
|
export default
|
||||||
@@ -18,16 +23,15 @@ angular.module('Users', [])
|
|||||||
.controller('UsersEdit', UsersEdit)
|
.controller('UsersEdit', UsersEdit)
|
||||||
.factory('UserForm', UserForm)
|
.factory('UserForm', UserForm)
|
||||||
.factory('UserList', UserList)
|
.factory('UserList', UserList)
|
||||||
.config(['$stateProvider', 'stateDefinitionsProvider',
|
.service('TokensStrings', TokensStrings)
|
||||||
function($stateProvider, stateDefinitionsProvider) {
|
|
||||||
let stateDefinitions = stateDefinitionsProvider.$get();
|
|
||||||
|
|
||||||
// lazily generate a tree of substates which will replace this node in ui-router's stateRegistry
|
.config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider',
|
||||||
// see: stateDefinition.factory for usage documentation
|
function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) {
|
||||||
$stateProvider.state({
|
let stateDefinitions = stateDefinitionsProvider.$get();
|
||||||
name: 'users.**',
|
let stateExtender = $stateExtenderProvider.$get();
|
||||||
url: '/users',
|
|
||||||
lazyLoad: () => stateDefinitions.generateTree({
|
function generateStateTree() {
|
||||||
|
let userTree = stateDefinitions.generateTree({
|
||||||
parent: 'users',
|
parent: 'users',
|
||||||
modes: ['add', 'edit'],
|
modes: ['add', 'edit'],
|
||||||
list: 'UserList',
|
list: 'UserList',
|
||||||
@@ -44,7 +48,28 @@ angular.module('Users', [])
|
|||||||
ncyBreadcrumb: {
|
ncyBreadcrumb: {
|
||||||
label: N_('USERS')
|
label: N_('USERS')
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
userTree
|
||||||
|
]).then((generated) => {
|
||||||
|
return {
|
||||||
|
states: _.reduce(generated, (result, definition) => {
|
||||||
|
return result.concat(definition.states);
|
||||||
|
}, [
|
||||||
|
stateExtender.buildDefinition(UserTokensListRoute),
|
||||||
|
stateExtender.buildDefinition(UserTokensAddRoute),
|
||||||
|
stateExtender.buildDefinition(UserTokensAddApplicationRoute)
|
||||||
|
])
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$stateProvider.state({
|
||||||
|
name: 'users.**',
|
||||||
|
url: '/users',
|
||||||
|
lazyLoad: () => generateStateTree()
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|||||||
12
awx/ui/client/src/users/token-modal.block.less
Normal file
12
awx/ui/client/src/users/token-modal.block.less
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/** @define TokenModal */
|
||||||
|
.TokenModal {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TokenModal-label {
|
||||||
|
font-weight: bold;
|
||||||
|
width: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TokenModal-value {
|
||||||
|
}
|
||||||
30
awx/ui/client/src/users/tokens.strings.js
Normal file
30
awx/ui/client/src/users/tokens.strings.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
function TokensStrings (BaseString) {
|
||||||
|
BaseString.call(this, 'tokens');
|
||||||
|
|
||||||
|
const { t } = this;
|
||||||
|
const ns = this.tokens;
|
||||||
|
|
||||||
|
ns.state = {
|
||||||
|
LIST_BREADCRUMB_LABEL: t.s('TOKENS'),
|
||||||
|
ADD_BREADCRUMB_LABEL: t.s('CREATE TOKEN'),
|
||||||
|
USER_LIST_BREADCRUMB_LABEL: t.s('TOKENS')
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.tab = {
|
||||||
|
DETAILS: t.s('Details')
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.add = {
|
||||||
|
PANEL_TITLE: t.s('CREATE TOKEN')
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.list = {
|
||||||
|
ROW_ITEM_LABEL_EXPIRED: t.s('DESCRIPTION'),
|
||||||
|
ROW_ITEM_LABEL_EXPIRED: t.s('EXPIRATION'),
|
||||||
|
ROW_ITEM_LABEL_USED: t.s('LAST USED')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
TokensStrings.$inject = ['BaseStringService'];
|
||||||
|
|
||||||
|
export default TokensStrings;
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
export default {
|
||||||
|
name: 'users.edit.tokens.add.application',
|
||||||
|
url: '/application?selected',
|
||||||
|
searchPrefix: 'application',
|
||||||
|
params: {
|
||||||
|
application_search: {
|
||||||
|
value: {
|
||||||
|
page_size: 5,
|
||||||
|
order_by: 'name'
|
||||||
|
},
|
||||||
|
dynamic: true,
|
||||||
|
squash: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
basePath: 'applications',
|
||||||
|
formChildState: true
|
||||||
|
},
|
||||||
|
ncyBreadcrumb: {
|
||||||
|
skip: true
|
||||||
|
},
|
||||||
|
views: {
|
||||||
|
'application@users.edit.tokens.add': {
|
||||||
|
templateProvider: (ListDefinition, generateList) => {
|
||||||
|
const html = generateList.build({
|
||||||
|
mode: 'lookup',
|
||||||
|
list: ListDefinition,
|
||||||
|
input_type: 'radio'
|
||||||
|
});
|
||||||
|
|
||||||
|
return `<lookup-modal>${html}</lookup-modal>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
ListDefinition: [() => {
|
||||||
|
return {
|
||||||
|
name: 'applications',
|
||||||
|
iterator: 'application',
|
||||||
|
hover: true,
|
||||||
|
index: false,
|
||||||
|
fields: {
|
||||||
|
name: {
|
||||||
|
key: true,
|
||||||
|
label: 'Name',
|
||||||
|
columnClass: 'col-lg-4 col-md-6 col-sm-8 col-xs-8',
|
||||||
|
awToolTip: '{{application.description | sanitize}}',
|
||||||
|
dataPlacement: 'top'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
},
|
||||||
|
fieldActions: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
Dataset: ['QuerySet', 'GetBasePath', '$stateParams', 'ListDefinition',
|
||||||
|
(qs, GetBasePath, $stateParams, list) => qs.search(
|
||||||
|
GetBasePath('applications'),
|
||||||
|
$stateParams[`${list.iterator}_search`]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
},
|
||||||
|
onExit ($state) {
|
||||||
|
if ($state.transition) {
|
||||||
|
$('#form-modal').modal('hide');
|
||||||
|
$('.modal-backdrop').remove();
|
||||||
|
$('body').removeClass('modal-open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
99
awx/ui/client/src/users/users-tokens-add.controller.js
Normal file
99
awx/ui/client/src/users/users-tokens-add.controller.js
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
function AddTokensController (models, $state, strings, Rest, Alert, Wait, GetBasePath, $filter) {
|
||||||
|
const vm = this || {};
|
||||||
|
const { application } = models;
|
||||||
|
|
||||||
|
vm.mode = 'add';
|
||||||
|
vm.strings = strings;
|
||||||
|
vm.panelTitle = strings.get('add.PANEL_TITLE');
|
||||||
|
|
||||||
|
vm.form = {};
|
||||||
|
|
||||||
|
vm.form.application = {
|
||||||
|
type: 'field',
|
||||||
|
label: 'Application',
|
||||||
|
id: 'application'
|
||||||
|
};
|
||||||
|
vm.form.description = {
|
||||||
|
type: 'String',
|
||||||
|
label: 'Description',
|
||||||
|
id: 'description'
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.form.application._resource = 'application';
|
||||||
|
vm.form.application._route = 'users.edit.tokens.add.application';
|
||||||
|
vm.form.application._model = application;
|
||||||
|
vm.form.application._placeholder = strings.get('SELECT AN APPLICATION');
|
||||||
|
vm.form.application.required = true;
|
||||||
|
|
||||||
|
vm.form.description.required = false;
|
||||||
|
|
||||||
|
vm.form.scope = {
|
||||||
|
choices: ['', 'read', 'write'],
|
||||||
|
help_text: 'Specify a scope for the token\'s access',
|
||||||
|
id: 'scope',
|
||||||
|
label: 'Scope',
|
||||||
|
required: true,
|
||||||
|
_component: 'at-input-select',
|
||||||
|
_data: ['', 'read', 'write'],
|
||||||
|
_exp: 'choice for (index, choice) in state._data',
|
||||||
|
_format: 'array'
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.form.save = data => {
|
||||||
|
Rest.setUrl(GetBasePath('users') + $state.params.user_id + '/authorized_tokens');
|
||||||
|
return Rest.post(data)
|
||||||
|
.then(({data}) => {
|
||||||
|
Alert('TOKEN INFORMATION', `
|
||||||
|
<div class="TokenModal">
|
||||||
|
<div class="TokenModal-label">
|
||||||
|
TOKEN
|
||||||
|
</div>
|
||||||
|
<div class="TokenModal-value">
|
||||||
|
${data.token}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="TokenModal">
|
||||||
|
<div class="TokenModal-label">
|
||||||
|
REFRESH TOKEN
|
||||||
|
</div>
|
||||||
|
<div class="TokenModal-value">
|
||||||
|
${data.refresh_token}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="TokenModal">
|
||||||
|
<div class="TokenModal-label">
|
||||||
|
EXPIRES
|
||||||
|
</div>
|
||||||
|
<div class="TokenModal-value">
|
||||||
|
${$filter('longDate')(data.expires)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`, null, null, null, null, null, true);
|
||||||
|
Wait('stop');
|
||||||
|
})
|
||||||
|
.catch(({data, status}) => {
|
||||||
|
ProcessErrors($scope, data, status, null, {
|
||||||
|
hdr: 'COULD NOT CREATE TOKEN',
|
||||||
|
msg: `Returned status: ${status}`
|
||||||
|
});
|
||||||
|
Wait('stop');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.form.onSaveSuccess = res => {
|
||||||
|
$state.go('^', { user_id: $state.params.user_id }, { reload: true });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AddTokensController.$inject = [
|
||||||
|
'resolvedModels',
|
||||||
|
'$state',
|
||||||
|
'ApplicationsStrings',
|
||||||
|
'Rest',
|
||||||
|
'Alert',
|
||||||
|
'Wait',
|
||||||
|
'GetBasePath',
|
||||||
|
'$filter'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default AddTokensController;
|
||||||
18
awx/ui/client/src/users/users-tokens-add.partial.html
Normal file
18
awx/ui/client/src/users/users-tokens-add.partial.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<at-panel>
|
||||||
|
<at-panel-heading>
|
||||||
|
{{ vm.panelTitle }}
|
||||||
|
</at-panel-heading>
|
||||||
|
|
||||||
|
<at-panel-body>
|
||||||
|
<at-form state="vm.form" autocomplete="off">
|
||||||
|
<at-input-lookup col="4" tab="1" state="vm.form.application"></at-input-lookup>
|
||||||
|
<at-input-text col="4" tab="2" state="vm.form.description"></at-input-text>
|
||||||
|
<at-input-select col="4" tab="3" state="vm.form.scope"></at-input-select>
|
||||||
|
|
||||||
|
<at-action-group col="12" pos="right">
|
||||||
|
<at-form-action type="cancel" to="tokens"></at-form-action>
|
||||||
|
<at-form-action type="save"></at-form-action>
|
||||||
|
</at-action-group>
|
||||||
|
</at-form>
|
||||||
|
</at-panel-body>
|
||||||
|
</at-panel>
|
||||||
38
awx/ui/client/src/users/users-tokens-add.route.js
Normal file
38
awx/ui/client/src/users/users-tokens-add.route.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { N_ } from '../i18n';
|
||||||
|
import AddController from './users-tokens-add.controller';
|
||||||
|
|
||||||
|
const addTemplate = require('~src/users/users-tokens-add.partial.html');
|
||||||
|
|
||||||
|
function TokensDetailResolve ($q, Application) {
|
||||||
|
|
||||||
|
const promises = {};
|
||||||
|
|
||||||
|
promises.application = new Application('options');
|
||||||
|
|
||||||
|
return $q.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
TokensDetailResolve.$inject = [
|
||||||
|
'$q',
|
||||||
|
'ApplicationModel'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
url: "/add-token",
|
||||||
|
name: 'users.edit.tokens.add',
|
||||||
|
params: {
|
||||||
|
},
|
||||||
|
ncyBreadcrumb: {
|
||||||
|
label: N_("ADD TOKEN")
|
||||||
|
},
|
||||||
|
views: {
|
||||||
|
'preFormView@users.edit': {
|
||||||
|
templateUrl: addTemplate,
|
||||||
|
controller: AddController,
|
||||||
|
controllerAs: 'vm'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
resolvedModels: TokensDetailResolve
|
||||||
|
}
|
||||||
|
};
|
||||||
119
awx/ui/client/src/users/users-tokens-list.controller.js
Normal file
119
awx/ui/client/src/users/users-tokens-list.controller.js
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/** ***********************************************
|
||||||
|
* Copyright (c) 2018 Ansible, Inc.
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
************************************************ */
|
||||||
|
function ListTokensController (
|
||||||
|
$filter,
|
||||||
|
$scope,
|
||||||
|
$state,
|
||||||
|
Dataset,
|
||||||
|
strings,
|
||||||
|
ProcessErrors,
|
||||||
|
Rest,
|
||||||
|
GetBasePath,
|
||||||
|
Prompt,
|
||||||
|
Wait
|
||||||
|
) {
|
||||||
|
const vm = this || {};
|
||||||
|
|
||||||
|
vm.strings = strings;
|
||||||
|
vm.activeId = $state.params.token_id;
|
||||||
|
|
||||||
|
$scope.canAdd = true;
|
||||||
|
|
||||||
|
// smart-search
|
||||||
|
const name = 'tokens';
|
||||||
|
const iterator = 'token';
|
||||||
|
const key = 'token_dataset';
|
||||||
|
|
||||||
|
$scope.list = { iterator, name, basePath: 'tokens' };
|
||||||
|
$scope.collection = { iterator };
|
||||||
|
$scope[key] = Dataset.data;
|
||||||
|
vm.tokensCount = Dataset.data.count;
|
||||||
|
$scope[name] = Dataset.data.results;
|
||||||
|
$scope.$on('updateDataset', (e, dataset) => {
|
||||||
|
$scope[key] = dataset;
|
||||||
|
$scope[name] = dataset.results;
|
||||||
|
vm.tokensCount = dataset.count;
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.getLastUsed = token => {
|
||||||
|
const lastUsed = _.get(token, 'last_used');
|
||||||
|
|
||||||
|
if (!lastUsed) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = $filter('longDate')(lastUsed);
|
||||||
|
|
||||||
|
const { username, id } = _.get(user, 'summary_fields.last_used', {});
|
||||||
|
|
||||||
|
if (username && id) {
|
||||||
|
html += ` by <a href="/#/users/${id}">${$filter('sanitize')(username)}</a>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html;
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.deleteToken = (tok) => {
|
||||||
|
const action = () => {
|
||||||
|
$('#prompt-modal').modal('hide');
|
||||||
|
Wait('start');
|
||||||
|
Rest.setUrl(`${GetBasePath('tokens')}${tok.id}`);
|
||||||
|
Rest.destroy()
|
||||||
|
.then(() => {
|
||||||
|
let reloadListStateParams = null;
|
||||||
|
|
||||||
|
if ($scope.tokens.length === 1 && $state.params.token_search &&
|
||||||
|
!_.isEmpty($state.params.token_search.page) &&
|
||||||
|
$state.params.token_search.page !== '1') {
|
||||||
|
const page = `${(parseInt(reloadListStateParams
|
||||||
|
.token_search.page, 10) - 1)}`;
|
||||||
|
reloadListStateParams = _.cloneDeep($state.params);
|
||||||
|
reloadListStateParams.token_search.page = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parseInt($state.params.token_id, 10) === tok.id) {
|
||||||
|
$state.go('^', reloadListStateParams, { reload: true });
|
||||||
|
} else {
|
||||||
|
$state.go('.', reloadListStateParams, { reload: true });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(({ data, status }) => {
|
||||||
|
ProcessErrors($scope, data, status, null, {
|
||||||
|
hdr: strings.get('error.HEADER'),
|
||||||
|
msg: strings.get('error.CALL', { path: `${GetBasePath('tokens')}${tok.id}`, status })
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
Wait('stop');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteModalBody = `<div class="Prompt-bodyQuery">${strings.get('deleteResource.CONFIRM', 'token')}</div>`;
|
||||||
|
|
||||||
|
Prompt({
|
||||||
|
hdr: strings.get('deleteResource.HEADER'),
|
||||||
|
resourceName: 'token',
|
||||||
|
body: deleteModalBody,
|
||||||
|
action,
|
||||||
|
actionText: 'DELETE'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ListTokensController.$inject = [
|
||||||
|
'$filter',
|
||||||
|
'$scope',
|
||||||
|
'$state',
|
||||||
|
'Dataset',
|
||||||
|
'TokensStrings',
|
||||||
|
'ProcessErrors',
|
||||||
|
'Rest',
|
||||||
|
'GetBasePath',
|
||||||
|
'Prompt',
|
||||||
|
'Wait'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default ListTokensController;
|
||||||
47
awx/ui/client/src/users/users-tokens-list.partial.html
Normal file
47
awx/ui/client/src/users/users-tokens-list.partial.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<div class="at-List-toolbar">
|
||||||
|
<smart-search
|
||||||
|
class="at-List-search"
|
||||||
|
django-model="tokens"
|
||||||
|
base-path="tokens"
|
||||||
|
iterator="token"
|
||||||
|
list="list"
|
||||||
|
dataset="token_dataset"
|
||||||
|
collection="collection"
|
||||||
|
search-tags="searchTags">
|
||||||
|
</smart-search>
|
||||||
|
<div class="at-List-toolbarAction">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
ui-sref=".add"
|
||||||
|
class="at-Button--add"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded="false">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<at-list results="tokens">
|
||||||
|
<at-row ng-repeat="token in tokens">
|
||||||
|
<div class="at-Row-items">
|
||||||
|
<at-row-item
|
||||||
|
header-value="{{ token.summary_fields.application.name }}">
|
||||||
|
</at-row-item>
|
||||||
|
<at-row-item
|
||||||
|
label-value="{{:: vm.strings.get('list.ROW_ITEM_LABEL_DESCRIPTION') }}"
|
||||||
|
value="{{ token.description }}">
|
||||||
|
</at-row-item>
|
||||||
|
<at-row-item
|
||||||
|
label-value="{{:: vm.strings.get('list.ROW_ITEM_LABEL_EXPIRED') }}"
|
||||||
|
value="{{ token.expriation | longDate }}">
|
||||||
|
</at-row-item>
|
||||||
|
<at-row-item
|
||||||
|
label-value="{{:: vm.strings.get('list.ROW_ITEM_LABEL_USED') }}"
|
||||||
|
value="{{ vm.getLastUsed(token) }}">
|
||||||
|
</at-row-item>
|
||||||
|
</div>
|
||||||
|
<div class="at-Row-actions">
|
||||||
|
<at-row-action icon="fa-trash" ng-click="vm.deleteToken(token)">
|
||||||
|
</at-row-action>
|
||||||
|
</div>
|
||||||
|
</at-row>
|
||||||
|
</at-list>
|
||||||
48
awx/ui/client/src/users/users-tokens-list.route.js
Normal file
48
awx/ui/client/src/users/users-tokens-list.route.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { N_ } from '../i18n';
|
||||||
|
|
||||||
|
import ListController from './users-tokens-list.controller';
|
||||||
|
|
||||||
|
const listTemplate = require('~src/users/users-tokens-list.partial.html');
|
||||||
|
|
||||||
|
export default {
|
||||||
|
url: "/tokens",
|
||||||
|
name: 'users.edit.tokens',
|
||||||
|
params: {
|
||||||
|
},
|
||||||
|
ncyBreadcrumb: {
|
||||||
|
label: N_("TOKENS")
|
||||||
|
},
|
||||||
|
views: {
|
||||||
|
'related': {
|
||||||
|
templateUrl: listTemplate,
|
||||||
|
controller: ListController,
|
||||||
|
controllerAs: 'vm'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
searchPrefix: 'token',
|
||||||
|
params: {
|
||||||
|
token_search: {
|
||||||
|
value: {
|
||||||
|
page_size: 5,
|
||||||
|
order_by: 'application'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
Dataset: [
|
||||||
|
'$stateParams',
|
||||||
|
'Wait',
|
||||||
|
'GetBasePath',
|
||||||
|
'QuerySet',
|
||||||
|
($stateParams, Wait, GetBasePath, qs) => {
|
||||||
|
const searchParam = $stateParams.token_search;
|
||||||
|
const searchPath = GetBasePath('users') + $stateParams.user_id + '/tokens';
|
||||||
|
Wait('start');
|
||||||
|
return qs.search(searchPath, searchParam)
|
||||||
|
.finally(() => {
|
||||||
|
Wait('stop');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -227,6 +227,11 @@ export default ['i18n', function(i18n) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
//hideOnSuperuser: true // RBAC defunct
|
//hideOnSuperuser: true // RBAC defunct
|
||||||
|
},
|
||||||
|
tokens: {
|
||||||
|
ngIf: 'isCurrentlyLoggedInUser',
|
||||||
|
title: i18n._('Tokens'),
|
||||||
|
skipGenerator: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user