mirror of
https://github.com/ansible/awx.git
synced 2026-05-08 01:47:35 -02:30
Add general error handling and submission
This commit is contained in:
@@ -29,8 +29,8 @@ function AddCredentialsController (models, $state) {
|
|||||||
return credential.request('post', data);
|
return credential.request('post', data);
|
||||||
};
|
};
|
||||||
|
|
||||||
vm.form.saveSuccess = res => {
|
vm.form.onSaveSuccess = res => {
|
||||||
$state.go('credentials.edit', { id: res.data.id });
|
$state.go('credentials.edit', { credential: res.data });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
<at-tab-group>
|
<at-tab-group>
|
||||||
<at-tab to="details">Details</at-tab>
|
<at-tab to="details">Details</at-tab>
|
||||||
<at-tab to="permissions">Permissions</at-tab>
|
<at-tab to="permissions">Permissions</at-tab>
|
||||||
<at-tab to="notifications">Notifications</at-tab>
|
|
||||||
</at-tab-group>
|
</at-tab-group>
|
||||||
|
|
||||||
<at-panel-body>
|
<at-panel-body>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
function EditCredentialsController (models, $state) {
|
||||||
|
let vm = this || {};
|
||||||
|
|
||||||
|
let me = models.me;
|
||||||
|
let credential = models.credential;
|
||||||
|
let credentialType = models.credentialType;
|
||||||
|
let credentialOptions = models.credentialOptions;
|
||||||
|
|
||||||
|
vm.form = credentialOptions.createFormSchema('put', {
|
||||||
|
omit: ['user', 'team', 'inputs'],
|
||||||
|
models
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.form.credential_type._data = credentialType.get('results');
|
||||||
|
vm.form.credential_type._placeholder = 'SELECT A TYPE';
|
||||||
|
vm.form.credential_type._format = 'grouped-object';
|
||||||
|
vm.form.credential_type._display = 'name';
|
||||||
|
vm.form.credential_type._key = 'id';
|
||||||
|
vm.form.credential_type._exp = 'type as type.name group by type.kind for type in state._data';
|
||||||
|
|
||||||
|
vm.form.inputs = {
|
||||||
|
_get: credentialType.mergeInputProperties,
|
||||||
|
_source: vm.form.credential_type,
|
||||||
|
_reference: 'vm.form.inputs',
|
||||||
|
_key: 'inputs'
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.form.save = data => {
|
||||||
|
data.user = me.get('results[0].id');
|
||||||
|
|
||||||
|
return credential.request('post', data);
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.form.onSaveSuccess = res => {
|
||||||
|
$state.go('credentials.edit', { credential: res.data });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
EditCredentialsController.$inject = [
|
||||||
|
'resolvedModels',
|
||||||
|
'$state'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default EditCredentialsController;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import CredentialList from './credentials.list.js';
|
import CredentialList from './credentials.list.js';
|
||||||
import ListController from './list/credentials-list.controller';
|
import ListController from './list/credentials-list.controller';
|
||||||
import AddController from './add-credentials.controller.js';
|
import AddController from './add-credentials.controller.js';
|
||||||
|
import EditController from './edit-credentials.controller.js';
|
||||||
import { N_ } from '../../src/i18n';
|
import { N_ } from '../../src/i18n';
|
||||||
|
|
||||||
function config ($stateExtenderProvider, pathServiceProvider) {
|
function config ($stateExtenderProvider, pathServiceProvider) {
|
||||||
@@ -41,32 +42,20 @@ function config ($stateExtenderProvider, pathServiceProvider) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function CredentialsResolve ($q, params, Me, Credential, CredentialType) {
|
function CredentialsResolve ($q, params, Me, Credential, CredentialType) {
|
||||||
let models;
|
|
||||||
let id = params.id;
|
|
||||||
let promises = {
|
let promises = {
|
||||||
me: new Me('get')
|
me: new Me('get')
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!id) {
|
if (params.credential) {
|
||||||
|
promises.credential = new Credential('get', params.credential);
|
||||||
|
promises.credentialOptions = new Credential('options');
|
||||||
|
promises.credentialType = new CredentialType('get', params.credential.credential_type);
|
||||||
|
} else {
|
||||||
promises.credential = new Credential('options');
|
promises.credential = new Credential('options');
|
||||||
promises.credentialType = new CredentialType('get');
|
promises.credentialType = new CredentialType('get');
|
||||||
|
|
||||||
return $q.all(promises).then(models => models);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
promises.credential = new Credential('get', id);
|
|
||||||
|
|
||||||
return $q.all(promises)
|
return $q.all(promises).then(models => models);
|
||||||
.then(_models_ => {
|
|
||||||
models = _models_;
|
|
||||||
|
|
||||||
return new CredentialType('get', models.credential.get('id'));
|
|
||||||
})
|
|
||||||
.then(credentialType => {
|
|
||||||
models.credentialType = credentialType;
|
|
||||||
|
|
||||||
return models;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CredentialsResolve.$inject = [
|
CredentialsResolve.$inject = [
|
||||||
@@ -85,7 +74,7 @@ function config ($stateExtenderProvider, pathServiceProvider) {
|
|||||||
},
|
},
|
||||||
views: {
|
views: {
|
||||||
'add@credentials': {
|
'add@credentials': {
|
||||||
templateUrl: pathService.getViewPath('credentials/add-credentials'),
|
templateUrl: pathService.getViewPath('credentials/add-edit-credentials'),
|
||||||
controller: AddController,
|
controller: AddController,
|
||||||
controllerAs: 'vm'
|
controllerAs: 'vm'
|
||||||
}
|
}
|
||||||
@@ -97,14 +86,14 @@ function config ($stateExtenderProvider, pathServiceProvider) {
|
|||||||
|
|
||||||
stateExtender.addState({
|
stateExtender.addState({
|
||||||
name: 'credentials.edit',
|
name: 'credentials.edit',
|
||||||
route: '/edit/:id',
|
route: '/edit/:credential',
|
||||||
ncyBreadcrumb: {
|
ncyBreadcrumb: {
|
||||||
label: N_('EDIT')
|
label: N_('EDIT')
|
||||||
},
|
},
|
||||||
views: {
|
views: {
|
||||||
'edit@credentials': {
|
'edit@credentials': {
|
||||||
templateUrl: pathService.getViewPath('credentials/add-credentials'),
|
templateUrl: pathService.getViewPath('credentials/add-edit-credentials'),
|
||||||
controller: AddController,
|
controller: EditController,
|
||||||
controllerAs: 'vm'
|
controllerAs: 'vm'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -124,4 +113,5 @@ angular
|
|||||||
.config(config)
|
.config(config)
|
||||||
.factory('CredentialList', CredentialList)
|
.factory('CredentialList', CredentialList)
|
||||||
.controller('ListController', ListController)
|
.controller('ListController', ListController)
|
||||||
.controller('AddController', AddController);
|
.controller('AddController', AddController)
|
||||||
|
.controller('EditController', EditController);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
@import 'action/_index';
|
@import 'action/_index';
|
||||||
@import 'input/_index';
|
@import 'input/_index';
|
||||||
@import 'panel/_index';
|
@import 'panel/_index';
|
||||||
|
@import 'modal/_index';
|
||||||
@import 'popover/_index';
|
@import 'popover/_index';
|
||||||
@import 'tabs/_index';
|
@import 'tabs/_index';
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ function AtFormController (eventService) {
|
|||||||
let form;
|
let form;
|
||||||
|
|
||||||
vm.components = [];
|
vm.components = [];
|
||||||
|
vm.modal = {};
|
||||||
vm.state = {
|
vm.state = {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
value: {}
|
value: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
vm.init = (_scope_, _form_) => {
|
vm.init = (_scope_, _form_) => {
|
||||||
@@ -76,7 +77,7 @@ function AtFormController (eventService) {
|
|||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
scope.state.save(data)
|
scope.state.save(data)
|
||||||
.then(scope.state.created)
|
.then(scope.state.onSaveSuccess)
|
||||||
.catch(err => vm.onSaveError(err))
|
.catch(err => vm.onSaveError(err))
|
||||||
.finally(() => vm.state.disabled = false);
|
.finally(() => vm.state.disabled = false);
|
||||||
};
|
};
|
||||||
@@ -89,7 +90,15 @@ function AtFormController (eventService) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
// TODO: launch modal for unexpected error type
|
let message;
|
||||||
|
|
||||||
|
if (typeof err.data === 'object') {
|
||||||
|
message = JSON.stringify(err.data);
|
||||||
|
} else {
|
||||||
|
message = err.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.modal.show('Unable to Submit', `Unexpected Error: ${message}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<form>
|
<div>
|
||||||
<div class="row">
|
<form>
|
||||||
<ng-transclude></ng-transclude>
|
<div class="row">
|
||||||
</div>
|
<ng-transclude></ng-transclude>
|
||||||
</form>
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<at-modal state="vm.modal"></at-modal>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import inputSecret from './input/secret.directive';
|
|||||||
import inputText from './input/text.directive';
|
import inputText from './input/text.directive';
|
||||||
import inputTextarea from './input/textarea.directive';
|
import inputTextarea from './input/textarea.directive';
|
||||||
import inputTextareaSecret from './input/textarea-secret.directive';
|
import inputTextareaSecret from './input/textarea-secret.directive';
|
||||||
|
import modal from './modal/modal.directive';
|
||||||
import panel from './panel/panel.directive';
|
import panel from './panel/panel.directive';
|
||||||
import panelHeading from './panel/heading.directive';
|
import panelHeading from './panel/heading.directive';
|
||||||
import panelBody from './panel/body.directive';
|
import panelBody from './panel/body.directive';
|
||||||
@@ -33,6 +34,7 @@ angular
|
|||||||
.directive('atInputText', inputText)
|
.directive('atInputText', inputText)
|
||||||
.directive('atInputTextarea', inputTextarea)
|
.directive('atInputTextarea', inputTextarea)
|
||||||
.directive('atInputTextareaSecret', inputTextareaSecret)
|
.directive('atInputTextareaSecret', inputTextareaSecret)
|
||||||
|
.directive('atModal', modal)
|
||||||
.directive('atPanel', panel)
|
.directive('atPanel', panel)
|
||||||
.directive('atPanelHeading', panelHeading)
|
.directive('atPanelHeading', panelHeading)
|
||||||
.directive('atPanelBody', panelBody)
|
.directive('atPanelBody', panelBody)
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ function AtInputSelectController (baseInputController, eventService) {
|
|||||||
[select, 'focus', () => input.classList.add('at-Input--focus')],
|
[select, 'focus', () => input.classList.add('at-Input--focus')],
|
||||||
[select, 'change', () => scope.$apply(() => {
|
[select, 'change', () => scope.$apply(() => {
|
||||||
scope.open = false;
|
scope.open = false;
|
||||||
|
vm.updateDisplayModel();
|
||||||
vm.check();
|
vm.check();
|
||||||
})],
|
})],
|
||||||
[select, 'blur', () => {
|
[select, 'blur', () => {
|
||||||
|
|||||||
@@ -8,14 +8,12 @@
|
|||||||
placeholder="{{state._placeholder || undefined }}"
|
placeholder="{{state._placeholder || undefined }}"
|
||||||
ng-class="{ 'at-Input--rejected': state._rejected }"
|
ng-class="{ 'at-Input--rejected': state._rejected }"
|
||||||
ng-model="displayModel"
|
ng-model="displayModel"
|
||||||
ng-disabled="state._disabled || form.disabled"
|
ng-disabled="state._disabled || form.disabled" />
|
||||||
ng-change="vm.check()" />
|
|
||||||
|
|
||||||
<select class="form-control at-InputSelect-select"
|
<select class="form-control at-InputSelect-select"
|
||||||
ng-model="state._value"
|
ng-model="state._value"
|
||||||
ng-attr-tabindex="{{ tab || undefined }}"
|
ng-attr-tabindex="{{ tab || undefined }}"
|
||||||
ng-disabled="state._disabled || form.disabled"
|
ng-disabled="state._disabled || form.disabled"
|
||||||
ng-change="vm.updateDisplayModel()"
|
|
||||||
ng-options="{{ state._exp }}">
|
ng-options="{{ state._exp }}">
|
||||||
<option style="display:none"></option>
|
<option style="display:none"></option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
10
awx/ui/client/lib/components/modal/_index.less
Normal file
10
awx/ui/client/lib/components/modal/_index.less
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
.at-Modal-title {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.at-mixin-Heading(@at-font-size-3x);
|
||||||
|
}
|
||||||
|
|
||||||
|
.at-Modal-body {
|
||||||
|
font-size: @at-font-size;
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
const DEFAULT_ANIMATION_DURATION = 150;
|
||||||
|
|
||||||
|
function atModalLink (scope, el, attr, controllers) {
|
||||||
|
let modalController = controllers[0];
|
||||||
|
let container = el[0];
|
||||||
|
|
||||||
|
modalController.init(scope, container);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AtModalController () {
|
||||||
|
let vm = this;
|
||||||
|
|
||||||
|
let scope;
|
||||||
|
let container;
|
||||||
|
|
||||||
|
vm.init = (_scope_, _container_) => {
|
||||||
|
scope = _scope_;
|
||||||
|
container = _container_;
|
||||||
|
|
||||||
|
scope.state.show = vm.show;
|
||||||
|
scope.state.hide = vm.hide;
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.show = (title, message) => {
|
||||||
|
scope.title = title;
|
||||||
|
scope.message = message;
|
||||||
|
|
||||||
|
container.style.display = 'block';
|
||||||
|
container.style.opacity = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.hide = () => {
|
||||||
|
container.style.opacity = 0;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
container.style.display = 'none';
|
||||||
|
scope.message = '';
|
||||||
|
scope.title = '';
|
||||||
|
}, DEFAULT_ANIMATION_DURATION);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function atModal (pathService) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
replace: true,
|
||||||
|
transclude: true,
|
||||||
|
require: ['atModal'],
|
||||||
|
templateUrl: pathService.getPartialPath('components/modal/modal'),
|
||||||
|
controller: AtModalController,
|
||||||
|
controllerAs: 'vm',
|
||||||
|
link: atModalLink,
|
||||||
|
scope: {
|
||||||
|
state: '='
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
atModal.$inject = [
|
||||||
|
'PathService'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default atModal;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<div class="modal at-Modal fade" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" ng-click="vm.hide()">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</button>
|
||||||
|
<h4 class="modal-title at-Modal-title">{{ title }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body at-Modal-body">
|
||||||
|
<p>{{ message }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn at-ButtonHollow--white" ng-click="vm.hide()">
|
||||||
|
OK
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function AtPopoverController () {
|
|||||||
vm.init = (scope, _container_, _icon_, _popover_) => {
|
vm.init = (scope, _container_, _icon_, _popover_) => {
|
||||||
icon = _icon_;
|
icon = _icon_;
|
||||||
popover = _popover_;
|
popover = _popover_;
|
||||||
scope.inline = scope.state._inline || true;
|
scope.inline = true;
|
||||||
|
|
||||||
icon.addEventListener('click', vm.createDisplayListener());
|
icon.addEventListener('click', vm.createDisplayListener());
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
let $http;
|
let $http;
|
||||||
|
let $q;
|
||||||
|
|
||||||
function request (method, ...args) {
|
function request (method, ...args) {
|
||||||
method = method.toUpperCase();
|
this.method = method.toUpperCase();
|
||||||
|
|
||||||
switch (method) {
|
if (typeof args[0] === 'object') {
|
||||||
|
this.res = null;
|
||||||
|
this.model = args[0];
|
||||||
|
|
||||||
|
return $q.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.method) {
|
||||||
case 'OPTIONS':
|
case 'OPTIONS':
|
||||||
return this.httpOptions(...args);
|
return this.httpOptions(...args);
|
||||||
case 'GET':
|
case 'GET':
|
||||||
@@ -112,12 +120,13 @@ function BaseModel (path) {
|
|||||||
this.path = this.normalizePath(path);
|
this.path = this.normalizePath(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
function BaseModelLoader (_$http_) {
|
function BaseModelLoader (_$http_, _$q_) {
|
||||||
$http = _$http_;
|
$http = _$http_;
|
||||||
|
$q = _$q_;
|
||||||
|
|
||||||
return BaseModel;
|
return BaseModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseModelLoader.$inject = ['$http'];
|
BaseModelLoader.$inject = ['$http', '$q'];
|
||||||
|
|
||||||
export default BaseModelLoader;
|
export default BaseModelLoader;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
let BaseModel;
|
let BaseModel;
|
||||||
|
|
||||||
function createFormSchema (type, config) {
|
function createFormSchema (method, config) {
|
||||||
let schema = Object.assign({}, this.get('actions.POST'));
|
method = method.toUpperCase();
|
||||||
|
|
||||||
|
let schema = Object.assign({}, this.get(`actions.${method}`));
|
||||||
|
|
||||||
if (config && config.omit) {
|
if (config && config.omit) {
|
||||||
config.omit.forEach(key => {
|
config.omit.forEach(key => {
|
||||||
|
|||||||
Reference in New Issue
Block a user