Compare commits
	
		
			16 commits
		
	
	
		
			clostridiu
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b3a5d1caa2 | |||
| 
							 | 
						14283f0c77 | ||
| 
							 | 
						3313b6e5f9 | ||
| 
							 | 
						8d4affd572 | ||
| 
							 | 
						e283f3f046 | ||
| 
							 | 
						0956ef3a25 | ||
| 
							 | 
						658304f728 | ||
| 
							 | 
						50cc073d2f | ||
| 
							 | 
						66c185e441 | ||
| 
							 | 
						df5a50b1e2 | ||
| 
							 | 
						689ea55bed | ||
| 
							 | 
						9496de21d9 | ||
| 
							 | 
						2811143066 | ||
| 
							 | 
						14698d0394 | ||
| 
							 | 
						233a2d09a1 | ||
| 
							 | 
						a4dbb4a94d | 
					 19 changed files with 13289 additions and 98 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -15,3 +15,4 @@
 | 
				
			||||||
/libpeerconnection.log
 | 
					/libpeerconnection.log
 | 
				
			||||||
npm-debug.log
 | 
					npm-debug.log
 | 
				
			||||||
testem.log
 | 
					testem.log
 | 
				
			||||||
 | 
					.firebase
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,10 @@ export default Mixin.create({
 | 
				
			||||||
  actions: {
 | 
					  actions: {
 | 
				
			||||||
    delete: function() {
 | 
					    delete: function() {
 | 
				
			||||||
      this.get('model').destroyRecord().then(() => {
 | 
					      this.get('model').destroyRecord().then(() => {
 | 
				
			||||||
        this.get('store').unloadAll();
 | 
					        // Instead of unloading the entire store, we keep the loaded user models
 | 
				
			||||||
 | 
					        ['species', 'strain', 'characteristic', 'measurement'].map((model) => {
 | 
				
			||||||
 | 
					          this.get('store').unloadAll(model);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
        this.transitionToRoute(this.get('transitionRoute'));
 | 
					        this.transitionToRoute(this.get('transitionRoute'));
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,3 +10,7 @@
 | 
				
			||||||
<div>
 | 
					<div>
 | 
				
			||||||
  {{link-to 'Forget your password?' 'users.requestlockouthelp'}}
 | 
					  {{link-to 'Forget your password?' 'users.requestlockouthelp'}}
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					<br>
 | 
				
			||||||
 | 
					<div>
 | 
				
			||||||
 | 
					  Just checking things out? Log in with email <code>read-only</code> and password <code>bacteria</code>!
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,36 +1,61 @@
 | 
				
			||||||
import Ember from 'ember';
 | 
					import Ember from 'ember';
 | 
				
			||||||
import SaveModel from '../../../../mixins/save-model';
 | 
					 | 
				
			||||||
import ajaxError from '../../../../utils/ajax-error';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { Controller } = Ember;
 | 
					const { Controller, RSVP, inject: { service } } = Ember;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Controller.extend({
 | 
				
			||||||
 | 
					  ajaxError: service('ajax-error'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Controller.extend(SaveModel, {
 | 
					 | 
				
			||||||
  // Required for SaveModel mixin
 | 
					 | 
				
			||||||
  fallbackRouteSave: 'protected.strains.show',
 | 
					  fallbackRouteSave: 'protected.strains.show',
 | 
				
			||||||
  fallbackRouteCancel: 'protected.strains.show',
 | 
					  fallbackRouteCancel: 'protected.strains.show',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  actions: {
 | 
					  actions: {
 | 
				
			||||||
    addCharacteristic: function() {
 | 
					    save: function(properties, deleteQueue, updateQueue) {
 | 
				
			||||||
      return this.store.createRecord('measurement', {
 | 
					      let promises = [];
 | 
				
			||||||
        characteristic: this.store.createRecord('characteristic', { sortOrder: -999 }),
 | 
					      properties.measurements.forEach((measurement) => {
 | 
				
			||||||
 | 
					        if (measurement.get('isNew')) {
 | 
				
			||||||
 | 
					          promises.push(measurement.save());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      updateQueue.forEach((measurement) => {
 | 
				
			||||||
 | 
					        promises.push(measurement.save());
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      deleteQueue.forEach((measurement) => {
 | 
				
			||||||
 | 
					        promises.push(measurement.destroyRecord());
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const model = this.get('model');
 | 
				
			||||||
 | 
					      const fallbackRoute = this.get('fallbackRouteSave');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      RSVP.all(promises).then(() => {
 | 
				
			||||||
 | 
					        // Can't call _super inside promise, have to reproduce save-model
 | 
				
			||||||
 | 
					        // mixin here :-(
 | 
				
			||||||
 | 
					        model.setProperties(properties);
 | 
				
			||||||
 | 
					        model.save().then((model) => {
 | 
				
			||||||
 | 
					          this.get('flashMessages').clearMessages();
 | 
				
			||||||
 | 
					          this.transitionToRoute(fallbackRoute, model);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }, (errors) => {
 | 
				
			||||||
 | 
					        this.get('ajaxError').alert(errors);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    saveMeasurement: function(measurement, properties) {
 | 
					    cancel: function() {
 | 
				
			||||||
      measurement.setProperties(properties);
 | 
					      const model = this.get('model');
 | 
				
			||||||
      measurement.save().then(() => {
 | 
					 | 
				
			||||||
        this.get('flashMessages').clearMessages();
 | 
					 | 
				
			||||||
      }, () => {
 | 
					 | 
				
			||||||
        ajaxError(measurement.get('errors'), this.get('flashMessages'));
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    deleteMeasurement: function(measurement) {
 | 
					      model.get('errors').clear();
 | 
				
			||||||
      const characteristic = measurement.get('characteristic');
 | 
					      model.rollbackAttributes();
 | 
				
			||||||
      if (characteristic.get('isNew')) {
 | 
					
 | 
				
			||||||
        characteristic.destroyRecord();
 | 
					      if (model.get('isNew')) {
 | 
				
			||||||
 | 
					        this.transitionToRoute(this.get('fallbackRouteCancel'));
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this.transitionToRoute(this.get('fallbackRouteCancel'), model);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      measurement.destroyRecord();
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    addMeasurement: function() {
 | 
				
			||||||
 | 
					      return this.store.createRecord('measurement');
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,8 @@
 | 
				
			||||||
  protected/strains/strain-form
 | 
					  protected/strains/strain-form
 | 
				
			||||||
  strain=model
 | 
					  strain=model
 | 
				
			||||||
  speciesList=speciesList
 | 
					  speciesList=speciesList
 | 
				
			||||||
  add-characteristic=(action "addCharacteristic")
 | 
					  add-measurement=(action "addMeasurement")
 | 
				
			||||||
  allCharacteristics=allCharacteristics
 | 
					  allCharacteristics=allCharacteristics
 | 
				
			||||||
  save-measurement=(action "saveMeasurement")
 | 
					 | 
				
			||||||
  delete-measurement=(action "deleteMeasurement")
 | 
					 | 
				
			||||||
  on-save=(action "save")
 | 
					  on-save=(action "save")
 | 
				
			||||||
  on-cancel=(action "cancel")
 | 
					  on-cancel=(action "cancel")
 | 
				
			||||||
}}
 | 
					}}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,8 @@ export default Component.extend({
 | 
				
			||||||
  allCharacteristics: null,
 | 
					  allCharacteristics: null,
 | 
				
			||||||
  measurement: null,
 | 
					  measurement: null,
 | 
				
			||||||
  isDirty: null,
 | 
					  isDirty: null,
 | 
				
			||||||
 | 
					  isNew: false,
 | 
				
			||||||
 | 
					  isQueued: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Actions
 | 
					  // Actions
 | 
				
			||||||
  "save-measurement": null,
 | 
					  "save-measurement": null,
 | 
				
			||||||
| 
						 | 
					@ -22,11 +24,23 @@ export default Component.extend({
 | 
				
			||||||
  notes: null,
 | 
					  notes: null,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  resetOnInit: Ember.on('init', function() {
 | 
					  resetOnInit: Ember.on('init', function() {
 | 
				
			||||||
 | 
					    this._resetProperties();
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _resetProperties: function() {
 | 
				
			||||||
    this.get('propertiesList').forEach((field) => {
 | 
					    this.get('propertiesList').forEach((field) => {
 | 
				
			||||||
      const valueInMeasurement = this.get('measurement').get(field);
 | 
					      const valueInMeasurement = this.get('measurement').get(field);
 | 
				
			||||||
      this.set(field, valueInMeasurement);
 | 
					      this.set(field, valueInMeasurement);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }),
 | 
					    // Read-only attributes
 | 
				
			||||||
 | 
					    this.set('isNew', this.get('measurement.isNew'));
 | 
				
			||||||
 | 
					    if (this.get('isNew') && !this.get('isQueued')) {
 | 
				
			||||||
 | 
					      this.set('isEditing', true);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.set('isEditing', false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.set('isDirty', false);
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateField: function(property, value) {
 | 
					  updateField: function(property, value) {
 | 
				
			||||||
    this.set(property, value);
 | 
					    this.set(property, value);
 | 
				
			||||||
| 
						 | 
					@ -40,12 +54,22 @@ export default Component.extend({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  actions: {
 | 
					  actions: {
 | 
				
			||||||
    edit: function() {
 | 
					    edit: function() {
 | 
				
			||||||
      this.toggleProperty('isEditing');
 | 
					      this.set('isEditing', true);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    save: function() {
 | 
					    save: function() {
 | 
				
			||||||
      this.attrs['save-measurement'](this.get('measurement'), this.getProperties(this.get('propertiesList')));
 | 
					      this.attrs['save-measurement'](this.get('measurement'), this.getProperties(this.get('propertiesList')));
 | 
				
			||||||
      this.toggleProperty('isEditing');
 | 
					      this.set('isQueued', true);
 | 
				
			||||||
 | 
					      this._resetProperties();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cancel: function() {
 | 
				
			||||||
 | 
					      if (this.get('isNew')) {
 | 
				
			||||||
 | 
					        this.attrs['delete-measurement'](this.get('measurement'));
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this._resetProperties();
 | 
				
			||||||
 | 
					        this.set('isEditing', false);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    delete: function() {
 | 
					    delete: function() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					{{loading-panel}}
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
{{#if isEditing}}
 | 
					{{#if isEditing}}
 | 
				
			||||||
  <td></td>
 | 
					  <td>
 | 
				
			||||||
 | 
					    {{{characteristic.characteristicTypeName}}}
 | 
				
			||||||
 | 
					  </td>
 | 
				
			||||||
  <td>
 | 
					  <td>
 | 
				
			||||||
    <select onchange={{action "characteristicDidChange" value="target.value"}}>
 | 
					    <select onchange={{action "characteristicDidChange" value="target.value"}}>
 | 
				
			||||||
      {{#each allCharacteristics as |characteristicChoice|}}
 | 
					      {{#each allCharacteristics as |characteristicChoice|}}
 | 
				
			||||||
| 
						 | 
					@ -15,14 +17,13 @@
 | 
				
			||||||
  </td>
 | 
					  </td>
 | 
				
			||||||
  {{#if canEdit}}
 | 
					  {{#if canEdit}}
 | 
				
			||||||
    <td>
 | 
					    <td>
 | 
				
			||||||
      {{#if isDirty}}
 | 
					      <button class="button-gray smaller" {{action 'cancel'}}>
 | 
				
			||||||
      <button class="button-green smaller" {{action 'save'}}>
 | 
					 | 
				
			||||||
        Save
 | 
					 | 
				
			||||||
      </button>
 | 
					 | 
				
			||||||
      {{else}}
 | 
					 | 
				
			||||||
      <button class="button-gray smaller" {{action 'save'}}>
 | 
					 | 
				
			||||||
        Cancel
 | 
					        Cancel
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
 | 
					      {{#if isDirty}}
 | 
				
			||||||
 | 
					        <button class="button-green smaller" {{action 'save'}}>
 | 
				
			||||||
 | 
					          Save
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
      {{/if}}
 | 
					      {{/if}}
 | 
				
			||||||
    </td>
 | 
					    </td>
 | 
				
			||||||
  {{/if}}
 | 
					  {{/if}}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,13 +5,13 @@ const { sort } = computed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Component.extend({
 | 
					export default Component.extend({
 | 
				
			||||||
  // Passed in
 | 
					  // Passed in
 | 
				
			||||||
  strain: null,
 | 
					  measurements: null,
 | 
				
			||||||
  allCharacteristics: null,
 | 
					  allCharacteristics: null,
 | 
				
			||||||
  canEdit: false,
 | 
					  canEdit: false,
 | 
				
			||||||
  canAdd: false,
 | 
					  canAdd: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Actions
 | 
					  // Actions
 | 
				
			||||||
  "add-characteristic": null,
 | 
					  "add-measurement": null,
 | 
				
			||||||
  "save-measurement": null,
 | 
					  "save-measurement": null,
 | 
				
			||||||
  "delete-measurement": null,
 | 
					  "delete-measurement": null,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,15 +19,11 @@ export default Component.extend({
 | 
				
			||||||
  sortParams: ['characteristic.characteristicTypeName', 'characteristic.sortOrder', 'characteristic.characteristicName'],
 | 
					  sortParams: ['characteristic.characteristicTypeName', 'characteristic.sortOrder', 'characteristic.characteristicName'],
 | 
				
			||||||
  sortAsc: true,
 | 
					  sortAsc: true,
 | 
				
			||||||
  paramsChanged: false,
 | 
					  paramsChanged: false,
 | 
				
			||||||
  sortedMeasurements: sort('strain.measurements', 'sortParams'),
 | 
					  sortedMeasurements: sort('measurements', 'sortParams'),
 | 
				
			||||||
  measurementsPresent: computed('strain.measurements', function() {
 | 
					 | 
				
			||||||
    return this.get('strain.measurements.length') > 0;
 | 
					 | 
				
			||||||
  }),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  actions: {
 | 
					  actions: {
 | 
				
			||||||
    addCharacteristic: function() {
 | 
					    addMeasurement: function() {
 | 
				
			||||||
      const newChar = this.attrs['add-characteristic']();
 | 
					      return this.attrs['add-measurement']();
 | 
				
			||||||
      this.get('strain.measurements').addObject(newChar);
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    changeSortParam: function(col) {
 | 
					    changeSortParam: function(col) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,16 @@
 | 
				
			||||||
{{#if canAdd}}
 | 
					{{#if canAdd}}
 | 
				
			||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <button class="button-green smaller" {{action "addCharacteristic"}}>
 | 
					  <button class="button-green smaller" {{action "addMeasurement"}}>
 | 
				
			||||||
    Add characteristic
 | 
					    Add measurement
 | 
				
			||||||
  </button>
 | 
					  </button>
 | 
				
			||||||
  <br><br>
 | 
					  <br><br>
 | 
				
			||||||
{{/if}}
 | 
					{{/if}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#if measurementsPresent}}
 | 
					{{#if paramsChanged}}
 | 
				
			||||||
  {{#if paramsChanged}}
 | 
					  <button class="button-gray smaller" {{action 'resetSortParam'}}>
 | 
				
			||||||
    <button class="button-gray smaller" {{action 'resetSortParam'}}>
 | 
					    Reset sort
 | 
				
			||||||
      Reset sort
 | 
					  </button>
 | 
				
			||||||
    </button>
 | 
					{{/if}}
 | 
				
			||||||
  {{/if}}
 | 
					 | 
				
			||||||
<table class="flakes-table">
 | 
					<table class="flakes-table">
 | 
				
			||||||
  <colgroup>
 | 
					  <colgroup>
 | 
				
			||||||
    {{#if canEdit}}
 | 
					    {{#if canEdit}}
 | 
				
			||||||
| 
						 | 
					@ -48,9 +47,10 @@
 | 
				
			||||||
        allCharacteristics=allCharacteristics
 | 
					        allCharacteristics=allCharacteristics
 | 
				
			||||||
        canEdit=canEdit
 | 
					        canEdit=canEdit
 | 
				
			||||||
      }}
 | 
					      }}
 | 
				
			||||||
 | 
					    {{else}}
 | 
				
			||||||
 | 
					      <tr>
 | 
				
			||||||
 | 
					        <td colspan="5">No Measurements on Record</td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
    {{/each}}
 | 
					    {{/each}}
 | 
				
			||||||
  </tbody>
 | 
					  </tbody>
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
{{else}}
 | 
					 | 
				
			||||||
No measurements on record.
 | 
					 | 
				
			||||||
{{/if}}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,11 +71,11 @@
 | 
				
			||||||
    {{! ROW 5 }}
 | 
					    {{! ROW 5 }}
 | 
				
			||||||
    <div class="grid-1 gutter-20">
 | 
					    <div class="grid-1 gutter-20">
 | 
				
			||||||
      <dl class="span-1">
 | 
					      <dl class="span-1">
 | 
				
			||||||
        <dt>Characteristics</dt>
 | 
					        <dt>Characteristic Measurements</dt>
 | 
				
			||||||
        <dd>
 | 
					        <dd>
 | 
				
			||||||
          {{
 | 
					          {{
 | 
				
			||||||
            protected/strains/measurements-table
 | 
					            protected/strains/measurements-table
 | 
				
			||||||
            strain=strain
 | 
					            measurements=strain.measurements
 | 
				
			||||||
            canEdit=false
 | 
					            canEdit=false
 | 
				
			||||||
            canAdd=false
 | 
					            canAdd=false
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,22 +9,22 @@ export default Component.extend(SetupMetaData, {
 | 
				
			||||||
  isNew: null,
 | 
					  isNew: null,
 | 
				
			||||||
  isDirty: false,
 | 
					  isDirty: false,
 | 
				
			||||||
  speciesList: null,
 | 
					  speciesList: null,
 | 
				
			||||||
  allCharacteristics: null,
 | 
					  allCharacteristics: [],
 | 
				
			||||||
 | 
					  updateQueue: [],
 | 
				
			||||||
 | 
					  deleteQueue: [],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Actions
 | 
					  // Actions
 | 
				
			||||||
  "on-save": null,
 | 
					  "on-save": null,
 | 
				
			||||||
  "on-cancel": null,
 | 
					  "on-cancel": null,
 | 
				
			||||||
  "on-update": null,
 | 
					  "on-update": null,
 | 
				
			||||||
  "add-characteristic": null,
 | 
					  "add-measurements": null,
 | 
				
			||||||
  "save-measurement": null,
 | 
					 | 
				
			||||||
  "delete-measurement": null,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // CPs
 | 
					  // CPs
 | 
				
			||||||
  sortParams: ['sortOrder'],
 | 
					  sortParams: ['sortOrder'],
 | 
				
			||||||
  sortedSpeciesList: sort('speciesList', 'sortParams'),
 | 
					  sortedSpeciesList: sort('speciesList', 'sortParams'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Property mapping
 | 
					  // Property mapping
 | 
				
			||||||
  propertiesList: ['strainName', 'typeStrain', 'species', 'isolatedFrom', 'accessionNumbers', 'genbank', 'wholeGenomeSequence', 'notes'],
 | 
					  propertiesList: ['strainName', 'typeStrain', 'species', 'isolatedFrom', 'accessionNumbers', 'genbank', 'wholeGenomeSequence', 'notes', 'measurements'],
 | 
				
			||||||
  strainName: null,
 | 
					  strainName: null,
 | 
				
			||||||
  typeStrain: null,
 | 
					  typeStrain: null,
 | 
				
			||||||
  species: null,
 | 
					  species: null,
 | 
				
			||||||
| 
						 | 
					@ -33,15 +33,55 @@ export default Component.extend(SetupMetaData, {
 | 
				
			||||||
  genbank: null,
 | 
					  genbank: null,
 | 
				
			||||||
  wholeGenomeSequence: null,
 | 
					  wholeGenomeSequence: null,
 | 
				
			||||||
  notes: null,
 | 
					  notes: null,
 | 
				
			||||||
 | 
					  measurements: [],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Dropdown menu
 | 
				
			||||||
 | 
					  characteristics: [],
 | 
				
			||||||
 | 
					  charSortParams: ['characteristicTypeName', 'sortOrder', 'characteristicName'],
 | 
				
			||||||
 | 
					  sortedCharacteristics: sort('characteristics', 'charSortParams'),
 | 
				
			||||||
 | 
					  setupCharacteristics: Ember.on('init', function() {
 | 
				
			||||||
 | 
					    const tempArray = this._resetArray(this.get('allCharacteristics'));
 | 
				
			||||||
 | 
					    this.set('characteristics', tempArray);
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  resetOnInit: Ember.on('init', function() {
 | 
					  resetOnInit: Ember.on('init', function() {
 | 
				
			||||||
 | 
					    this._resetProperties();
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _resetArray: function(arr) {
 | 
				
			||||||
 | 
					    let tempArray = [];
 | 
				
			||||||
 | 
					    arr.forEach((val) => {
 | 
				
			||||||
 | 
					      if (!val.get('isNew')) {
 | 
				
			||||||
 | 
					        tempArray.push(val);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return tempArray;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _resetProperties: function() {
 | 
				
			||||||
 | 
					    // Still some coupling going on here because of adding strain to measurement
 | 
				
			||||||
 | 
					    this.get('measurements').forEach((val) => {
 | 
				
			||||||
 | 
					      if (val.get('hasDirtyAttributes')) {
 | 
				
			||||||
 | 
					        val.rollbackAttributes();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (val.get('isNew')) {
 | 
				
			||||||
 | 
					        this.get('strain.measurements').removeObject(val);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    this.get('propertiesList').forEach((field) => {
 | 
					    this.get('propertiesList').forEach((field) => {
 | 
				
			||||||
      const valueInStrain = this.get('strain').get(field);
 | 
					      const valueInStrain = this.get('strain').get(field);
 | 
				
			||||||
      this.set(field, valueInStrain);
 | 
					      if (field === 'measurements') {
 | 
				
			||||||
 | 
					        const tempArray = this._resetArray(valueInStrain);
 | 
				
			||||||
 | 
					        this.set(field, tempArray);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this.set(field, valueInStrain);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    this.set('updateQueue', []);
 | 
				
			||||||
 | 
					    this.set('deleteQueue', []);
 | 
				
			||||||
    // Read-only attributes
 | 
					    // Read-only attributes
 | 
				
			||||||
    this.set('isNew', this.get('strain.isNew'));
 | 
					    this.set('isNew', this.get('strain.isNew'));
 | 
				
			||||||
  }),
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateField: function(property, value) {
 | 
					  updateField: function(property, value) {
 | 
				
			||||||
    this.set(property, value);
 | 
					    this.set(property, value);
 | 
				
			||||||
| 
						 | 
					@ -55,23 +95,32 @@ export default Component.extend(SetupMetaData, {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  actions: {
 | 
					  actions: {
 | 
				
			||||||
    save: function() {
 | 
					    save: function() {
 | 
				
			||||||
      return this.attrs['on-save'](this.getProperties(this.get('propertiesList')));
 | 
					      return this.attrs['on-save'](this.getProperties(this.get('propertiesList')), this.get('deleteQueue'), this.get('updateQueue'));
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cancel: function() {
 | 
					    cancel: function() {
 | 
				
			||||||
 | 
					      this._resetProperties();
 | 
				
			||||||
      return this.attrs['on-cancel']();
 | 
					      return this.attrs['on-cancel']();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addCharacteristic: function() {
 | 
					    addMeasurement: function() {
 | 
				
			||||||
      return this.attrs['add-characteristic']();
 | 
					      const measurement = this.attrs['add-measurement']();
 | 
				
			||||||
 | 
					      this.get('measurements').pushObject(measurement);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    saveMeasurement: function(measurement, properties) {
 | 
					    saveMeasurement: function(measurement, properties) {
 | 
				
			||||||
      return this.attrs['save-measurement'](measurement, properties);
 | 
					      measurement.setProperties(properties);
 | 
				
			||||||
 | 
					      measurement.set('strain', this.get('strain'));
 | 
				
			||||||
 | 
					      if (!measurement.get('isNew')) {
 | 
				
			||||||
 | 
					        this.get('updateQueue').pushObject(measurement);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.set('isDirty', true);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    deleteMeasurement: function(measurement) {
 | 
					    deleteMeasurement: function(measurement) {
 | 
				
			||||||
      return this.attrs['delete-measurement'](measurement);
 | 
					      this.get('deleteQueue').pushObject(measurement);
 | 
				
			||||||
 | 
					      this.get('measurements').removeObject(measurement);
 | 
				
			||||||
 | 
					      this.set('isDirty', true);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    strainNameDidChange: function(value) {
 | 
					    strainNameDidChange: function(value) {
 | 
				
			||||||
| 
						 | 
					@ -104,7 +153,7 @@ export default Component.extend(SetupMetaData, {
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    notesDidChange: function(value) {
 | 
					    notesDidChange: function(value) {
 | 
				
			||||||
      this.updateField('strain.notes', value);
 | 
					      this.updateField('notes', value);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,9 +61,9 @@
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      {{
 | 
					      {{
 | 
				
			||||||
        protected/strains/measurements-table
 | 
					        protected/strains/measurements-table
 | 
				
			||||||
        strain=strain
 | 
					        measurements=measurements
 | 
				
			||||||
        add-characteristic=(action "addCharacteristic")
 | 
					        add-measurement=(action "addMeasurement")
 | 
				
			||||||
        allCharacteristics=allCharacteristics
 | 
					        allCharacteristics=sortedCharacteristics
 | 
				
			||||||
        save-measurement=(action "saveMeasurement")
 | 
					        save-measurement=(action "saveMeasurement")
 | 
				
			||||||
        delete-measurement=(action "deleteMeasurement")
 | 
					        delete-measurement=(action "deleteMeasurement")
 | 
				
			||||||
        canEdit=strain.canEdit
 | 
					        canEdit=strain.canEdit
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
import Ember from 'ember';
 | 
					import Ember from 'ember';
 | 
				
			||||||
import ajaxErrorNew from '../../../../utils/ajax-error-new';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { Controller, inject: { service } } = Ember;
 | 
					const { Controller, inject: { service } } = Ember;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Controller.extend({
 | 
					export default Controller.extend({
 | 
				
			||||||
  session: service(),
 | 
					  session: service(),
 | 
				
			||||||
  ajax: service(),
 | 
					  ajax: service(),
 | 
				
			||||||
 | 
					  ajaxError: service('ajax-error'),
 | 
				
			||||||
  currentUser: service('session-account'),
 | 
					  currentUser: service('session-account'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  actions: {
 | 
					  actions: {
 | 
				
			||||||
| 
						 | 
					@ -15,12 +15,13 @@ export default Controller.extend({
 | 
				
			||||||
      this.get('ajax').post('/users/password', { data: data }).then(() => {
 | 
					      this.get('ajax').post('/users/password', { data: data }).then(() => {
 | 
				
			||||||
        this.transitionToRoute('protected.users.show', id);
 | 
					        this.transitionToRoute('protected.users.show', id);
 | 
				
			||||||
        this.get('flashMessages').information('Your password has been changed.');
 | 
					        this.get('flashMessages').information('Your password has been changed.');
 | 
				
			||||||
      }, (error) => {
 | 
					      }, (errors) => {
 | 
				
			||||||
        ajaxErrorNew(error, this.get('flashMessages'));
 | 
					        this.get('ajaxError').alert(errors);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cancel: function() {
 | 
					    cancel: function() {
 | 
				
			||||||
 | 
					      this.get('flashMessages').clearMessages();
 | 
				
			||||||
      this.transitionToRoute('protected.users.show', this.get('currentUser.account.id'));
 | 
					      this.transitionToRoute('protected.users.show', this.get('currentUser.account.id'));
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,24 +5,41 @@ const { RESTSerializer } = DS;
 | 
				
			||||||
const { isNone } = Ember;
 | 
					const { isNone } = Ember;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default RESTSerializer.extend({
 | 
					export default RESTSerializer.extend({
 | 
				
			||||||
  isNewSerializerAPI: true,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  serializeBelongsTo: function(snapshot, json, relationship) {
 | 
					  serializeBelongsTo: function(snapshot, json, relationship) {
 | 
				
			||||||
    let key = relationship.key;
 | 
					    const key = relationship.key;
 | 
				
			||||||
    const belongsTo = snapshot.belongsTo(key);
 | 
					    if (this._canSerialize(key)) {
 | 
				
			||||||
    key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo", "serialize") : key;
 | 
					      const belongsToId = snapshot.belongsTo(key, { id: true });
 | 
				
			||||||
    json[key] = isNone(belongsTo) ? belongsTo : +belongsTo.record.id;
 | 
					      let payloadKey = this._getMappedKey(key, snapshot.type);
 | 
				
			||||||
 | 
					      if (payloadKey === key && this.keyForRelationship) {
 | 
				
			||||||
 | 
					        payloadKey = this.keyForRelationship(key, "belongsTo", "serialize");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (isNone(belongsToId)) {
 | 
				
			||||||
 | 
					        json[payloadKey] = null;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        json[payloadKey] = +belongsToId;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (relationship.options.polymorphic) {
 | 
				
			||||||
 | 
					        this.serializePolymorphicType(snapshot, json, relationship);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  serializeHasMany: function(snapshot, json, relationship) {
 | 
					  serializeHasMany: function(snapshot, json, relationship) {
 | 
				
			||||||
    let key = relationship.key;
 | 
					    const key = relationship.key;
 | 
				
			||||||
    const hasMany = snapshot.hasMany(key);
 | 
					    if (this._shouldSerializeHasMany(snapshot, key, relationship)) {
 | 
				
			||||||
    key = this.keyForRelationship ? this.keyForRelationship(key, "hasMany", "serialize") : key;
 | 
					      const hasMany = snapshot.hasMany(key, { ids: true });
 | 
				
			||||||
 | 
					      if (hasMany !== undefined) {
 | 
				
			||||||
    json[key] = [];
 | 
					        let payloadKey = this._getMappedKey(key, snapshot.type);
 | 
				
			||||||
    hasMany.forEach((item) => {
 | 
					        if (payloadKey === key && this.keyForRelationship) {
 | 
				
			||||||
      json[key].push(+item.id);
 | 
					          payloadKey = this.keyForRelationship(key, "hasMany", "serialize");
 | 
				
			||||||
    });
 | 
					        }
 | 
				
			||||||
 | 
					        json[payloadKey] = [];
 | 
				
			||||||
 | 
					        hasMany.forEach((item) => {
 | 
				
			||||||
 | 
					          json[payloadKey].push(+item);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								app/services/ajax-error.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/services/ajax-error.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					import Ember from 'ember';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { Service, inject: { service } } = Ember;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Service.extend({
 | 
				
			||||||
 | 
					  flashMessages: service(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  alert: function(error) {
 | 
				
			||||||
 | 
					    const flash = this.get('flashMessages');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flash.clearMessages();
 | 
				
			||||||
 | 
					    window.scrollTo(0,0);
 | 
				
			||||||
 | 
					    error.errors.forEach((error) => {
 | 
				
			||||||
 | 
					      console.error(error);
 | 
				
			||||||
 | 
					      const source = error.source.pointer.split('/');
 | 
				
			||||||
 | 
					      flash.error(`${source[source.length-1].replace(/([A-Z])/g, ' $1').capitalize()} - ${error.detail}`);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
| 
						 | 
					@ -1,7 +0,0 @@
 | 
				
			||||||
export default function ajaxErrorNew(error, flash) {
 | 
					 | 
				
			||||||
  flash.clearMessages();
 | 
					 | 
				
			||||||
  error.errors.forEach((error) => {
 | 
					 | 
				
			||||||
    const source = error.source.pointer.split('/');
 | 
					 | 
				
			||||||
    flash.error(`${source[source.length-1].replace(/([A-Z])/g, ' $1').capitalize()} - ${error.detail}`);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										13051
									
								
								package-lock.json
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										13051
									
								
								package-lock.json
									
										
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										10
									
								
								package.json
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								package.json
									
										
									
									
									
								
							| 
						 | 
					@ -10,7 +10,11 @@
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "build": "ember build",
 | 
					    "build": "ember build",
 | 
				
			||||||
    "start": "ember server",
 | 
					    "start": "ember server",
 | 
				
			||||||
    "test": "ember test"
 | 
					    "test": "ember test",
 | 
				
			||||||
 | 
					    "bower": "bower",
 | 
				
			||||||
 | 
					    "ember": "ember",
 | 
				
			||||||
 | 
					    "firebase": "firebase",
 | 
				
			||||||
 | 
					    "deployProd": "firebase deploy -e prod"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": "",
 | 
					  "repository": "",
 | 
				
			||||||
  "engines": {
 | 
					  "engines": {
 | 
				
			||||||
| 
						 | 
					@ -40,5 +44,9 @@
 | 
				
			||||||
    "ember-export-application-global": "^1.0.4",
 | 
					    "ember-export-application-global": "^1.0.4",
 | 
				
			||||||
    "ember-one-way-input": "0.1.3",
 | 
					    "ember-one-way-input": "0.1.3",
 | 
				
			||||||
    "ember-simple-auth": "1.0.1"
 | 
					    "ember-simple-auth": "1.0.1"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "bower": "^1.8.8",
 | 
				
			||||||
 | 
					    "firebase-tools": "^7.12.1"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in a new issue