parent
							
								
									e1abc5e4cb
								
							
						
					
					
						commit
						f41f4caccd
					
				
					 17 changed files with 221 additions and 77 deletions
				
			
		| 
						 | 
				
			
			@ -9,4 +9,11 @@ export default JSONAPIAdapter.extend(DataAdapterMixin, {
 | 
			
		|||
  namespace: API_NAMESPACE,
 | 
			
		||||
  host: API_HOST,
 | 
			
		||||
  authorizer: 'authorizer:application',
 | 
			
		||||
  // DRF-JSON-API returns 400 by default
 | 
			
		||||
  handleResponse(status, headers, payload) {
 | 
			
		||||
    if (status === 400 && payload.errors) {
 | 
			
		||||
      return new DS.InvalidError(payload.errors);
 | 
			
		||||
    }
 | 
			
		||||
    return this._super(...arguments);
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import Ember from 'ember';
 | 
			
		||||
import Changeset from 'ember-changeset';
 | 
			
		||||
import lookupValidator from 'ember-changeset-validations';
 | 
			
		||||
 | 
			
		||||
const { Component } = Ember;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7,6 +8,7 @@ export default Component.extend({
 | 
			
		|||
  init() {
 | 
			
		||||
    this._super(...arguments);
 | 
			
		||||
    const model = this.get('model');
 | 
			
		||||
    this.set('changeset', new Changeset(model));
 | 
			
		||||
    const validations = this.get('validations');
 | 
			
		||||
    this.set('changeset', new Changeset(model, lookupValidator(validations), validations));
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								app/components/validated-field.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/components/validated-field.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
import Ember from 'ember';
 | 
			
		||||
 | 
			
		||||
const { Component, computed, get, isEmpty } = Ember;
 | 
			
		||||
 | 
			
		||||
export default Component.extend({
 | 
			
		||||
  classNames: ['form-group'],
 | 
			
		||||
  classNameBindings: ['isValid::has-error'],
 | 
			
		||||
 | 
			
		||||
  isValid: computed('changeset.error', 'property', function() {
 | 
			
		||||
    const changeset = this.get('changeset');
 | 
			
		||||
    const property = this.get('property');
 | 
			
		||||
    return isEmpty(get(changeset, `error.${property}`));
 | 
			
		||||
  }),
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,16 +1,21 @@
 | 
			
		|||
import Ember from 'ember';
 | 
			
		||||
import CollectionValidations from '../../validations/collection';
 | 
			
		||||
import { schema } from '../../models/collection';
 | 
			
		||||
import ValidationMixin from '../../mixins/validation';
 | 
			
		||||
 | 
			
		||||
const { Controller } = Ember;
 | 
			
		||||
 | 
			
		||||
export default Controller.extend({
 | 
			
		||||
export default Controller.extend(ValidationMixin, {
 | 
			
		||||
  CollectionValidations,
 | 
			
		||||
 | 
			
		||||
  actions: {
 | 
			
		||||
    onSave(changeset) {
 | 
			
		||||
      changeset.save();
 | 
			
		||||
      this.transitionToRoute('collections.index');
 | 
			
		||||
      const postSave = () => { this.transitionToRoute('collections.index'); };
 | 
			
		||||
      return this.validationSave(changeset, schema, postSave);
 | 
			
		||||
    },
 | 
			
		||||
    onCancel(changeset) {
 | 
			
		||||
      changeset.rollback();
 | 
			
		||||
      this.transitionToRoute('collections.index');
 | 
			
		||||
      const postCancel = () => { this.transitionToRoute('collections.index'); };
 | 
			
		||||
      return this.validationCancel(changeset, postCancel);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										27
									
								
								app/controllers/collections/detail/edit.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								app/controllers/collections/detail/edit.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
import Ember from 'ember';
 | 
			
		||||
import CollectionValidations from '../../../validations/collection';
 | 
			
		||||
import { schema } from '../../../models/collection';
 | 
			
		||||
import ValidationMixin from '../../../mixins/validation';
 | 
			
		||||
 | 
			
		||||
const { Controller } = Ember;
 | 
			
		||||
 | 
			
		||||
export default Controller.extend(ValidationMixin, {
 | 
			
		||||
  CollectionValidations,
 | 
			
		||||
 | 
			
		||||
  actions: {
 | 
			
		||||
    onSave(changeset) {
 | 
			
		||||
      const postSave = () => {
 | 
			
		||||
        // Use the model's ID here because of the ArrayProxy in the route
 | 
			
		||||
        this.transitionToRoute('collections.detail', this.get('model.id'));
 | 
			
		||||
      };
 | 
			
		||||
      return this.validationSave(changeset, schema, postSave);
 | 
			
		||||
    },
 | 
			
		||||
    onCancel(changeset) {
 | 
			
		||||
      const postCancel = () => {
 | 
			
		||||
        // Use the model's ID here because of the ArrayProxy in the route
 | 
			
		||||
        return this.transitionToRoute('collections.detail', this.get('model.id'));
 | 
			
		||||
      };
 | 
			
		||||
      return this.validationCancel(changeset, postCancel);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										11
									
								
								app/controllers/collections/detail/index.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/controllers/collections/detail/index.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
import Ember from 'ember';
 | 
			
		||||
 | 
			
		||||
const { Controller } = Ember;
 | 
			
		||||
 | 
			
		||||
export default Controller.extend({
 | 
			
		||||
  actions: {
 | 
			
		||||
    editCollection() {
 | 
			
		||||
      this.transitionToRoute('collections.detail.edit', this.get('model'));
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										30
									
								
								app/mixins/validation.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								app/mixins/validation.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
import Ember from 'ember';
 | 
			
		||||
 | 
			
		||||
const { Mixin, get } = Ember;
 | 
			
		||||
const { keys } = Object;
 | 
			
		||||
 | 
			
		||||
export default Mixin.create({
 | 
			
		||||
  validationSave(changeset, schema, postSave) {
 | 
			
		||||
    return changeset
 | 
			
		||||
      .cast(keys(schema))
 | 
			
		||||
      .validate()
 | 
			
		||||
      .then(() => {
 | 
			
		||||
        if (changeset.get('isValid')) {
 | 
			
		||||
          return changeset.save().then(postSave);
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      .catch((error) => {
 | 
			
		||||
        /* eslint-disable no-console */
 | 
			
		||||
        console.log(error);
 | 
			
		||||
        /* eslint-enable no-console */
 | 
			
		||||
        get(this, 'model.errors').forEach(({ attribute, message }) => {
 | 
			
		||||
          changeset.pushErrors(attribute, message);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  validationCancel(changeset, postCancel) {
 | 
			
		||||
      changeset.rollback();
 | 
			
		||||
      return postCancel();
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,9 @@ Router.map(function() {
 | 
			
		|||
  this.route('logout');
 | 
			
		||||
  this.route('collections', function() {
 | 
			
		||||
    this.route('create');
 | 
			
		||||
    this.route('detail', { path: '/:collection_id' });
 | 
			
		||||
    this.route('detail', { path: '/:collection_id' }, function() {
 | 
			
		||||
      this.route('edit');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								app/routes/collections/detail/edit.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								app/routes/collections/detail/edit.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
import Ember from 'ember';
 | 
			
		||||
 | 
			
		||||
const { Route, RSVP } = Ember;
 | 
			
		||||
 | 
			
		||||
export default Route.extend({
 | 
			
		||||
  model() {
 | 
			
		||||
    const store = this.get('store');
 | 
			
		||||
    const model = this.modelFor('collections.detail');
 | 
			
		||||
    return RSVP.hash({
 | 
			
		||||
      model: model,
 | 
			
		||||
      projectOptions: store.findAll('project'),
 | 
			
		||||
      studyLocationOptions: store.findAll('study-location'),
 | 
			
		||||
      collectionTypeOptions: store.findAll('collection-type'),
 | 
			
		||||
      collectionMethodOptions: store.findAll('collection-method'),
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  setupController(controller, models) {
 | 
			
		||||
    this._super(...arguments);
 | 
			
		||||
    // Unwrap the parent route's listified model
 | 
			
		||||
    models.model = models.model[0];
 | 
			
		||||
    controller.setProperties(models);
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
{{
 | 
			
		||||
  collection-create-container
 | 
			
		||||
  model=model
 | 
			
		||||
  validations=CollectionValidations
 | 
			
		||||
  projectOptions=projectOptions
 | 
			
		||||
  studyLocationOptions=studyLocationOptions
 | 
			
		||||
  collectionTypeOptions=collectionTypeOptions
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
{{collection-detail-container model=model}}
 | 
			
		||||
							
								
								
									
										11
									
								
								app/templates/collections/detail/edit.hbs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/templates/collections/detail/edit.hbs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
{{
 | 
			
		||||
  collection-create-container
 | 
			
		||||
  model=model
 | 
			
		||||
  validations=CollectionValidations
 | 
			
		||||
  projectOptions=projectOptions
 | 
			
		||||
  studyLocationOptions=studyLocationOptions
 | 
			
		||||
  collectionTypeOptions=collectionTypeOptions
 | 
			
		||||
  collectionMethodOptions=collectionMethodOptions
 | 
			
		||||
  onSave=(action 'onSave')
 | 
			
		||||
  onCancel=(action 'onCancel')
 | 
			
		||||
}}
 | 
			
		||||
							
								
								
									
										5
									
								
								app/templates/collections/detail/index.hbs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/templates/collections/detail/index.hbs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
{{
 | 
			
		||||
  collection-detail-container
 | 
			
		||||
  model=model
 | 
			
		||||
  editCollection=(action 'editCollection')
 | 
			
		||||
}}
 | 
			
		||||
| 
						 | 
				
			
			@ -4,10 +4,8 @@
 | 
			
		|||
  onCancel=(action onCancel) as |f|
 | 
			
		||||
}}
 | 
			
		||||
  <div class="well">
 | 
			
		||||
    {{#f.content class='form-horizontal'}}
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <label class="col-md-2 control-label">Project</label>
 | 
			
		||||
        <div class="col-md-10">
 | 
			
		||||
    {{#f.content class='form'}}
 | 
			
		||||
      {{#validated-field property='project' label='Project' changeset=changeset}}
 | 
			
		||||
        {{#power-select
 | 
			
		||||
          options=projectOptions
 | 
			
		||||
          selected=changeset.project
 | 
			
		||||
| 
						 | 
				
			
			@ -17,12 +15,9 @@
 | 
			
		|||
        }}
 | 
			
		||||
          {{project.name}}
 | 
			
		||||
        {{/power-select}}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{/validated-field}}
 | 
			
		||||
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <label class="col-md-2 control-label">Study location</label>
 | 
			
		||||
        <div class="col-md-10">
 | 
			
		||||
      {{#validated-field property='studyLocation' label='Study location' changeset=changeset}}
 | 
			
		||||
          {{#power-select
 | 
			
		||||
            options=studyLocationOptions
 | 
			
		||||
            selected=changeset.studyLocation
 | 
			
		||||
| 
						 | 
				
			
			@ -32,12 +27,9 @@
 | 
			
		|||
          }}
 | 
			
		||||
            {{studyLocation.name}}
 | 
			
		||||
          {{/power-select}}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{/validated-field}}
 | 
			
		||||
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <label class="col-md-2 control-label">Collection type</label>
 | 
			
		||||
        <div class="col-md-10">
 | 
			
		||||
      {{#validated-field property='collectionType' label='Collection type' changeset=changeset}}
 | 
			
		||||
          {{#power-select
 | 
			
		||||
            options=collectionTypeOptions
 | 
			
		||||
            selected=changeset.collectionType
 | 
			
		||||
| 
						 | 
				
			
			@ -47,12 +39,9 @@
 | 
			
		|||
          }}
 | 
			
		||||
            {{collectionType.name}}
 | 
			
		||||
          {{/power-select}}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{/validated-field}}
 | 
			
		||||
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <label class="col-md-2 control-label">Collection method</label>
 | 
			
		||||
        <div class="col-md-10">
 | 
			
		||||
      {{#validated-field property='collectionMethod' label='Collection method' changeset=changeset}}
 | 
			
		||||
        {{#power-select
 | 
			
		||||
          options=collectionMethodOptions
 | 
			
		||||
          selected=changeset.collectionMethod
 | 
			
		||||
| 
						 | 
				
			
			@ -62,43 +51,27 @@
 | 
			
		|||
        }}
 | 
			
		||||
          {{collectionMethod.name}}
 | 
			
		||||
        {{/power-select}}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{/validated-field}}
 | 
			
		||||
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <label class="col-md-2 control-label">Number of traps</label>
 | 
			
		||||
        <div class="col-md-10">
 | 
			
		||||
      {{#validated-field property='numberOfTraps' label='Number of traps' changeset=changeset}}
 | 
			
		||||
        {{input value=changeset.numberOfTraps type='number' class='form-control'}}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{/validated-field}}
 | 
			
		||||
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <label class="col-md-2 control-label">Collection start date</label>
 | 
			
		||||
        <div class="col-md-10">
 | 
			
		||||
      {{#validated-field property='collectionStartDate' label='Collection start date' changeset=changeset}}
 | 
			
		||||
        {{input value=changeset.collectionStartDate type='date' class='form-control'}}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{/validated-field}}
 | 
			
		||||
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <label class="col-md-2 control-label">Collection start time</label>
 | 
			
		||||
        <div class="col-md-10">
 | 
			
		||||
      {{#validated-field property='collectionStartTime' label='Collection start time' changeset=changeset}}
 | 
			
		||||
        {{input value=changeset.collectionStartTime type='time' class='form-control'}}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{/validated-field}}
 | 
			
		||||
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <label class="col-md-2 control-label">Collection end date</label>
 | 
			
		||||
        <div class="col-md-10">
 | 
			
		||||
      {{#validated-field property='collectionEndDate' label='Collection end date' changeset=changeset}}
 | 
			
		||||
        {{input value=changeset.collectionEndDate type='date' class='form-control'}}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{/validated-field}}
 | 
			
		||||
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <label class="col-md-2 control-label">Collection end time</label>
 | 
			
		||||
        <div class="col-md-10">
 | 
			
		||||
      {{#validated-field property='collectionEndTime' label='Collection end time' changeset=changeset}}
 | 
			
		||||
        {{input value=changeset.collectionEndTime type='time' class='form-control'}}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{/validated-field}}
 | 
			
		||||
 | 
			
		||||
    {{/f.content}}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,10 @@
 | 
			
		|||
{{
 | 
			
		||||
  action-button
 | 
			
		||||
  isPrimary=true
 | 
			
		||||
  label='Edit Collection'
 | 
			
		||||
  onClick=(action editCollection)
 | 
			
		||||
}}
 | 
			
		||||
 | 
			
		||||
{{#ccdb-table model=model columns=columns as |c|}}
 | 
			
		||||
  {{#c.grid as |g|}}
 | 
			
		||||
    {{g.head}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								app/templates/components/validated-field.hbs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/templates/components/validated-field.hbs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
<label class="control-label">{{label}}</label>
 | 
			
		||||
{{yield}}
 | 
			
		||||
 | 
			
		||||
{{#if (get changeset.error property)}}
 | 
			
		||||
  <ul class="help-block">
 | 
			
		||||
    {{#each (get (get changeset.error property) "validation") as |message|}}
 | 
			
		||||
      <li>{{message}}</li>
 | 
			
		||||
    {{/each}}
 | 
			
		||||
  </ul>
 | 
			
		||||
{{/if}}
 | 
			
		||||
							
								
								
									
										16
									
								
								app/validations/collection.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/validations/collection.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
import {
 | 
			
		||||
  validatePresence,
 | 
			
		||||
  validateNumber,
 | 
			
		||||
} from 'ember-changeset-validations/validators';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  project:             validatePresence(true),
 | 
			
		||||
  studyLocation:       validatePresence(true),
 | 
			
		||||
  collectionMethod:    validatePresence(true),
 | 
			
		||||
  collectionType:      validatePresence(true),
 | 
			
		||||
  numberOfTraps:       validateNumber({ allowBlank: true, integer: true, positive: true }),
 | 
			
		||||
 | 
			
		||||
  collectionStartDate: validatePresence(true),
 | 
			
		||||
  collectionEndDate:   validatePresence(true),
 | 
			
		||||
  // TODO: Fix time formats
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue