Add general error handling and submission

This commit is contained in:
gconsidine 2017-06-07 17:28:48 -04:00
parent 40dbe56932
commit add48f3f14
16 changed files with 196 additions and 44 deletions

View File

@ -29,8 +29,8 @@ function AddCredentialsController (models, $state) {
return credential.request('post', data);
};
vm.form.saveSuccess = res => {
$state.go('credentials.edit', { id: res.data.id });
vm.form.onSaveSuccess = res => {
$state.go('credentials.edit', { credential: res.data });
};
}

View File

@ -4,7 +4,6 @@
<at-tab-group>
<at-tab to="details">Details</at-tab>
<at-tab to="permissions">Permissions</at-tab>
<at-tab to="notifications">Notifications</at-tab>
</at-tab-group>
<at-panel-body>

View File

@ -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;

View File

@ -1,6 +1,7 @@
import CredentialList from './credentials.list.js';
import ListController from './list/credentials-list.controller';
import AddController from './add-credentials.controller.js';
import EditController from './edit-credentials.controller.js';
import { N_ } from '../../src/i18n';
function config ($stateExtenderProvider, pathServiceProvider) {
@ -41,32 +42,20 @@ function config ($stateExtenderProvider, pathServiceProvider) {
});
function CredentialsResolve ($q, params, Me, Credential, CredentialType) {
let models;
let id = params.id;
let promises = {
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.credentialType = new CredentialType('get');
return $q.all(promises).then(models => models);
}
promises.credential = new Credential('get', id);
return $q.all(promises)
.then(_models_ => {
models = _models_;
return new CredentialType('get', models.credential.get('id'));
})
.then(credentialType => {
models.credentialType = credentialType;
return models;
});
return $q.all(promises).then(models => models);
}
CredentialsResolve.$inject = [
@ -85,7 +74,7 @@ function config ($stateExtenderProvider, pathServiceProvider) {
},
views: {
'add@credentials': {
templateUrl: pathService.getViewPath('credentials/add-credentials'),
templateUrl: pathService.getViewPath('credentials/add-edit-credentials'),
controller: AddController,
controllerAs: 'vm'
}
@ -97,14 +86,14 @@ function config ($stateExtenderProvider, pathServiceProvider) {
stateExtender.addState({
name: 'credentials.edit',
route: '/edit/:id',
route: '/edit/:credential',
ncyBreadcrumb: {
label: N_('EDIT')
},
views: {
'edit@credentials': {
templateUrl: pathService.getViewPath('credentials/add-credentials'),
controller: AddController,
templateUrl: pathService.getViewPath('credentials/add-edit-credentials'),
controller: EditController,
controllerAs: 'vm'
}
},
@ -124,4 +113,5 @@ angular
.config(config)
.factory('CredentialList', CredentialList)
.controller('ListController', ListController)
.controller('AddController', AddController);
.controller('AddController', AddController)
.controller('EditController', EditController);

View File

@ -1,5 +1,6 @@
@import 'action/_index';
@import 'input/_index';
@import 'panel/_index';
@import 'modal/_index';
@import 'popover/_index';
@import 'tabs/_index';

View File

@ -12,10 +12,11 @@ function AtFormController (eventService) {
let form;
vm.components = [];
vm.modal = {};
vm.state = {
isValid: false,
disabled: false,
value: {}
value: {},
};
vm.init = (_scope_, _form_) => {
@ -76,7 +77,7 @@ function AtFormController (eventService) {
}, {});
scope.state.save(data)
.then(scope.state.created)
.then(scope.state.onSaveSuccess)
.catch(err => vm.onSaveError(err))
.finally(() => vm.state.disabled = false);
};
@ -89,7 +90,15 @@ function AtFormController (eventService) {
}
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}`);
}
};

View File

@ -1,5 +1,9 @@
<form>
<div class="row">
<ng-transclude></ng-transclude>
</div>
</form>
<div>
<form>
<div class="row">
<ng-transclude></ng-transclude>
</div>
</form>
<at-modal state="vm.modal"></at-modal>
</div>

View File

@ -10,6 +10,7 @@ import inputSecret from './input/secret.directive';
import inputText from './input/text.directive';
import inputTextarea from './input/textarea.directive';
import inputTextareaSecret from './input/textarea-secret.directive';
import modal from './modal/modal.directive';
import panel from './panel/panel.directive';
import panelHeading from './panel/heading.directive';
import panelBody from './panel/body.directive';
@ -33,6 +34,7 @@ angular
.directive('atInputText', inputText)
.directive('atInputTextarea', inputTextarea)
.directive('atInputTextareaSecret', inputTextareaSecret)
.directive('atModal', modal)
.directive('atPanel', panel)
.directive('atPanelHeading', panelHeading)
.directive('atPanelBody', panelBody)

View File

@ -36,6 +36,7 @@ function AtInputSelectController (baseInputController, eventService) {
[select, 'focus', () => input.classList.add('at-Input--focus')],
[select, 'change', () => scope.$apply(() => {
scope.open = false;
vm.updateDisplayModel();
vm.check();
})],
[select, 'blur', () => {

View File

@ -8,14 +8,12 @@
placeholder="{{state._placeholder || undefined }}"
ng-class="{ 'at-Input--rejected': state._rejected }"
ng-model="displayModel"
ng-disabled="state._disabled || form.disabled"
ng-change="vm.check()" />
ng-disabled="state._disabled || form.disabled" />
<select class="form-control at-InputSelect-select"
ng-model="state._value"
ng-attr-tabindex="{{ tab || undefined }}"
ng-disabled="state._disabled || form.disabled"
ng-change="vm.updateDisplayModel()"
ng-options="{{ state._exp }}">
<option style="display:none"></option>
</select>

View 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;
}

View File

@ -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;

View File

@ -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>

View File

@ -17,7 +17,7 @@ function AtPopoverController () {
vm.init = (scope, _container_, _icon_, _popover_) => {
icon = _icon_;
popover = _popover_;
scope.inline = scope.state._inline || true;
scope.inline = true;
icon.addEventListener('click', vm.createDisplayListener());
};

View File

@ -1,9 +1,17 @@
let $http;
let $q;
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':
return this.httpOptions(...args);
case 'GET':
@ -112,12 +120,13 @@ function BaseModel (path) {
this.path = this.normalizePath(path);
};
function BaseModelLoader (_$http_) {
function BaseModelLoader (_$http_, _$q_) {
$http = _$http_;
$q = _$q_;
return BaseModel;
}
BaseModelLoader.$inject = ['$http'];
BaseModelLoader.$inject = ['$http', '$q'];
export default BaseModelLoader;

View File

@ -1,7 +1,9 @@
let BaseModel;
function createFormSchema (type, config) {
let schema = Object.assign({}, this.get('actions.POST'));
function createFormSchema (method, config) {
method = method.toUpperCase();
let schema = Object.assign({}, this.get(`actions.${method}`));
if (config && config.omit) {
config.omit.forEach(key => {