diff --git a/app/helpers/equal.js b/app/helpers/equal.js new file mode 100644 index 0000000..db3e867 --- /dev/null +++ b/app/helpers/equal.js @@ -0,0 +1,7 @@ +import Ember from 'ember'; + +export function equalHelper(params) { + return params[0] === params[1]; +} + +export default Ember.HTMLBars.makeBoundHelper(equalHelper); diff --git a/app/models/user.js b/app/models/user.js index bb7c5fd..680a9f4 100644 --- a/app/models/user.js +++ b/app/models/user.js @@ -5,6 +5,7 @@ export default DS.Model.extend({ password : DS.attr('string'), name : DS.attr('string'), role : DS.attr('string'), + canEdit : DS.attr('boolean'), createdAt: DS.attr('date'), updatedAt: DS.attr('date'), deletedAt: DS.attr('date'), diff --git a/app/pods/application/adapter.js b/app/pods/application/adapter.js index 0a943ec..11498d0 100644 --- a/app/pods/application/adapter.js +++ b/app/pods/application/adapter.js @@ -1,5 +1,4 @@ import DS from 'ember-data'; -import Ember from 'ember'; export default DS.RESTAdapter.extend({ namespace: function() { @@ -12,24 +11,6 @@ export default DS.RESTAdapter.extend({ coalesceFindRequests: true, - ajaxError: function(jqXHR) { - // http://stackoverflow.com/a/24027443 - var error = this._super(jqXHR); - if (jqXHR && jqXHR.status === 422) { - var response = Ember.$.parseJSON(jqXHR.responseText), - errors = {}; - if (response.errors !== undefined) { - var jsonErrors = response.errors; - Ember.EnumerableUtils.forEach(Object.keys(jsonErrors), function(key) { - errors[Ember.String.camelize(key)] = jsonErrors[key]; - }); - } - return new DS.InvalidError(errors); - } else { - return error; - } - }, - shouldReloadAll: function() { return true; }, diff --git a/app/pods/components/delete-button/component.js b/app/pods/components/delete-button/component.js new file mode 100644 index 0000000..2ceca5b --- /dev/null +++ b/app/pods/components/delete-button/component.js @@ -0,0 +1,13 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + tagName: 'button', + classNames: ["button-red", "smaller"], + + click: function() { + if (window.confirm("Do you really want to delete this?")) { + this.attrs.delete(); + } + }, + +}); diff --git a/app/pods/components/delete-button/template.hbs b/app/pods/components/delete-button/template.hbs new file mode 100644 index 0000000..4b2e04f --- /dev/null +++ b/app/pods/components/delete-button/template.hbs @@ -0,0 +1 @@ +Delete diff --git a/app/pods/protected/characteristics/show/controller.js b/app/pods/protected/characteristics/show/controller.js new file mode 100644 index 0000000..cc45d06 --- /dev/null +++ b/app/pods/protected/characteristics/show/controller.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; + +export default Ember.Controller.extend({ + actions: { + delete: function() { + this.get('model').destroyRecord() + this.transitionToRoute('protected.characteristics.index'); + }, + }, + +}); diff --git a/app/pods/protected/characteristics/show/template.hbs b/app/pods/protected/characteristics/show/template.hbs index de81623..010a8c5 100644 --- a/app/pods/protected/characteristics/show/template.hbs +++ b/app/pods/protected/characteristics/show/template.hbs @@ -26,6 +26,7 @@
Measurements
+

To add/edit/remove a measurement, please visit the strain's page (links below)

{{protected/characteristics/show/measurements-table model=model}}
@@ -54,4 +55,5 @@ {{#link-to 'protected.characteristics.edit' model.id class="button-gray smaller"}} Edit {{/link-to}} + {{delete-button delete=(action 'delete')}} {{/if}} diff --git a/app/pods/protected/species/show/controller.js b/app/pods/protected/species/show/controller.js new file mode 100644 index 0000000..cadc1f4 --- /dev/null +++ b/app/pods/protected/species/show/controller.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; + +export default Ember.Controller.extend({ + actions: { + delete: function() { + this.get('model').destroyRecord(); + this.transitionToRoute('protected.species.index'); + }, + }, + +}); diff --git a/app/pods/protected/species/show/template.hbs b/app/pods/protected/species/show/template.hbs index 059ab04..528b969 100644 --- a/app/pods/protected/species/show/template.hbs +++ b/app/pods/protected/species/show/template.hbs @@ -62,4 +62,5 @@ {{#link-to 'protected.species.edit' model class="button-gray smaller"}} Edit {{/link-to}} + {{delete-button delete=(action 'delete')}} {{/if}} diff --git a/app/pods/protected/strains/edit/route.js b/app/pods/protected/strains/edit/route.js index 94a7710..6bb9b2f 100644 --- a/app/pods/protected/strains/edit/route.js +++ b/app/pods/protected/strains/edit/route.js @@ -17,6 +17,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { setupController: function(controller, models) { controller.setProperties(models); + controller.set('metaData', this.store.metadataFor('strain')); }, }); diff --git a/app/pods/protected/strains/edit/template.hbs b/app/pods/protected/strains/edit/template.hbs index d9c4d43..a4885d6 100644 --- a/app/pods/protected/strains/edit/template.hbs +++ b/app/pods/protected/strains/edit/template.hbs @@ -2,6 +2,7 @@ protected/strains/strain-form strain=strain species=species + canAdd=metaData.canAdd save="save" cancel="cancel" }} diff --git a/app/pods/protected/strains/show/controller.js b/app/pods/protected/strains/show/controller.js new file mode 100644 index 0000000..ab4d552 --- /dev/null +++ b/app/pods/protected/strains/show/controller.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; + +export default Ember.Controller.extend({ + actions: { + delete: function() { + this.get('model').destroyRecord(); + this.transitionToRoute('protected.strains.index'); + }, + }, + +}); diff --git a/app/pods/protected/strains/show/measurements-table-row/component.js b/app/pods/protected/strains/show/measurements-table-row/component.js index 252e6e3..a527572 100644 --- a/app/pods/protected/strains/show/measurements-table-row/component.js +++ b/app/pods/protected/strains/show/measurements-table-row/component.js @@ -4,6 +4,16 @@ export default Ember.Component.extend({ tagName: 'tr', isEditing: false, + oldCharacteristicId: function() { + let json = this.get('row').toJSON(); + return json.characteristic; + }.property(), + + rowChanged: Ember.computed('row.notes', 'row.value', 'row.characteristic.id', function() { + return this.get('row.hasDirtyAttributes') || + this.get('oldCharacteristicId') !== this.get('row.characteristic.id'); + }), + actions: { edit: function() { // The parent table fetches all of the characteristics ahead of time @@ -13,8 +23,14 @@ export default Ember.Component.extend({ save: function() { this.toggleProperty('isEditing'); - this.get('row').save(); + if (this.get('rowChanged')) { + this.get('row').save(); + } }, - + + delete: function() { + this.get('row').destroyRecord(); + } + }, }); diff --git a/app/pods/protected/strains/show/measurements-table-row/template.hbs b/app/pods/protected/strains/show/measurements-table-row/template.hbs index bdf8566..1c6cc07 100644 --- a/app/pods/protected/strains/show/measurements-table-row/template.hbs +++ b/app/pods/protected/strains/show/measurements-table-row/template.hbs @@ -16,9 +16,15 @@ {{#if canEdit}} - + {{else}} + + {{/if}} {{/if}} {{else}} @@ -38,6 +44,7 @@ + {{delete-button delete=(action 'delete')}} {{/if}} {{/if}} diff --git a/app/pods/protected/strains/show/measurements-table/component.js b/app/pods/protected/strains/show/measurements-table/component.js index af846d0..8d8e31d 100644 --- a/app/pods/protected/strains/show/measurements-table/component.js +++ b/app/pods/protected/strains/show/measurements-table/component.js @@ -11,7 +11,19 @@ export default Ember.Component.extend({ } }.on('didInsertElement'), - sortParams: ['characteristicTypeName', 'sortOrder', 'characteristicName'], + sortParams: ['characteristic.characteristicTypeName', 'characteristic.sortOrder', 'characteristic.characteristicName'], sortedMeasurements: Ember.computed.sort('model.measurements', 'sortParams'), + actions: { + addCharacteristic: function() { + const c = this.store.createRecord('characteristic', { + sortOrder: -999 + }); + const m = this.store.createRecord('measurement', { + characteristic: c + }); + this.get('model.measurements').addObject(m); + }, + }, + }); diff --git a/app/pods/protected/strains/show/measurements-table/template.hbs b/app/pods/protected/strains/show/measurements-table/template.hbs index 3f14ca7..2f30a9e 100644 --- a/app/pods/protected/strains/show/measurements-table/template.hbs +++ b/app/pods/protected/strains/show/measurements-table/template.hbs @@ -1,11 +1,19 @@ +{{#if canAdd}} +
+ +

+{{/if}} + {{#if measurementsPresent}} {{#if canEdit}} - - + + {{else}} diff --git a/app/pods/protected/strains/show/template.hbs b/app/pods/protected/strains/show/template.hbs index dbe09fe..5260d43 100644 --- a/app/pods/protected/strains/show/template.hbs +++ b/app/pods/protected/strains/show/template.hbs @@ -77,6 +77,7 @@ protected/strains/show/measurements-table model=model canEdit=false + canAdd=false }} @@ -104,4 +105,5 @@ {{#link-to 'protected.strains.edit' model.id class="button-gray smaller"}} Edit {{/link-to}} + {{delete-button delete=(action 'delete')}} {{/if}} diff --git a/app/pods/protected/strains/strain-form/template.hbs b/app/pods/protected/strains/strain-form/template.hbs index 8260411..cf33026 100644 --- a/app/pods/protected/strains/strain-form/template.hbs +++ b/app/pods/protected/strains/strain-form/template.hbs @@ -54,6 +54,7 @@ protected/strains/show/measurements-table model=strain canEdit=strain.canEdit + canAdd=canAdd }}
diff --git a/app/pods/protected/users/changepassword/controller.js b/app/pods/protected/users/changepassword/controller.js new file mode 100644 index 0000000..a157605 --- /dev/null +++ b/app/pods/protected/users/changepassword/controller.js @@ -0,0 +1,29 @@ +import Ember from 'ember'; +import ajaxRequest from '../../../../utils/ajax-request'; + +export default Ember.Controller.extend({ + passwordConfirm: null, + + actions: { + save: function() { + if (this.get('password') !== this.get('passwordConfirm')) { + this.get('flashMessages').clearMessages(); + this.get('flashMessages').error("Password fields don't match"); + return; + } + + let url = `${this.get('globals.apiURL')}/api/${this.get('globals.genus')}/users/password`; + let options = { + method: 'POST', + data: { + password: this.get('password'), + }, + }; + ajaxRequest(url, options); + this.transitionTo('protected.users.index'); + this.get('flashMessages').information('Your password has been changed.'); + }, + + }, + +}); diff --git a/app/pods/protected/users/changepassword/route.js b/app/pods/protected/users/changepassword/route.js new file mode 100644 index 0000000..982b827 --- /dev/null +++ b/app/pods/protected/users/changepassword/route.js @@ -0,0 +1,12 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + beforeModel: function(transition) { + this._super(transition); + + let user_id = transition.params['protected.users.changepassword'].user_id; + if (this.get('session.currentUser.id') !== user_id) { + this.transitionTo('protected.users.index'); + } + } +}); diff --git a/app/pods/protected/users/changepassword/template.hbs b/app/pods/protected/users/changepassword/template.hbs new file mode 100644 index 0000000..b22db6c --- /dev/null +++ b/app/pods/protected/users/changepassword/template.hbs @@ -0,0 +1,24 @@ +
+
+
+ Change password +
+
    +
  • + + {{input type="password" value=password}} +
  • +
  • + + {{input type="password" value=passwordConfirm}} +
  • +
  • + +
  • +
+ +
+
+
diff --git a/app/pods/protected/users/edit/controller.js b/app/pods/protected/users/edit/controller.js new file mode 100644 index 0000000..3d4940c --- /dev/null +++ b/app/pods/protected/users/edit/controller.js @@ -0,0 +1,41 @@ +import Ember from 'ember'; + +export default Ember.Controller.extend({ + actions: { + save: function() { + let user = this.get('model'); + + if (user.get('hasDirtyAttributes')) { + let attrs = user.changedAttributes(), roleChanged = false; + if (attrs.role) { + roleChanged = true; + } + user.save().then((user) => { + this.get('flashMessages').clearMessages(); + if (roleChanged) { + // Need to clear the store so that canEdit and canAdd + // attributes reflect the new role. + this.get('store').unloadAll(); + } + this.transitionToRoute('protected.users.show', user); + }, (err) => { + err.errors.forEach((error) => { + this.get('flashMessages').error(error.detail); + }); + }); + } else { + this.transitionToRoute('protected.users.show', user); + } + }, + + cancel: function() { + let user = this.get('model'); + + user.get('errors').clear(); + user.rollbackAttributes(); + + this.transitionToRoute('protected.users.show', user); + }, + + }, +}); diff --git a/app/pods/protected/users/edit/route.js b/app/pods/protected/users/edit/route.js new file mode 100644 index 0000000..bc22dc0 --- /dev/null +++ b/app/pods/protected/users/edit/route.js @@ -0,0 +1,8 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + model: function(params) { + return this.store.findRecord('user', params.user_id, { reload: true }); + }, + +}); diff --git a/app/pods/protected/users/edit/template.hbs b/app/pods/protected/users/edit/template.hbs new file mode 100644 index 0000000..2f2f678 --- /dev/null +++ b/app/pods/protected/users/edit/template.hbs @@ -0,0 +1,7 @@ +{{ + protected/users/user-form + user=model + currentUser=session.currentUser + save="save" + cancel="cancel" +}} diff --git a/app/pods/protected/users/show/controller.js b/app/pods/protected/users/show/controller.js new file mode 100644 index 0000000..481b126 --- /dev/null +++ b/app/pods/protected/users/show/controller.js @@ -0,0 +1,7 @@ +import Ember from 'ember'; + +export default Ember.Controller.extend({ + isUser: Ember.computed('model.id', 'session.currentUser.id', function() { + return this.get('model.id') === this.get('session.currentUser.id'); + }), +}); diff --git a/app/pods/protected/users/show/template.hbs b/app/pods/protected/users/show/template.hbs index 32117c9..9d21912 100644 --- a/app/pods/protected/users/show/template.hbs +++ b/app/pods/protected/users/show/template.hbs @@ -38,12 +38,20 @@
-{{#link-to 'protected.users.show' model.id class="button-gray smaller"}} - Change Password (Does nothing at the moment) -{{/link-to}} -{{#if model.canEdit}} -
- {{#link-to 'protected.user.edit' model.id class="button-gray smaller"}} - Edit - {{/link-to}} -{{/if}} +
+ {{#if isUser}} +
+ {{#link-to 'protected.users.changepassword' model.id class="button-gray smaller"}} + Change Password + {{/link-to}} +
+ {{/if}} + +
+ {{#if model.canEdit}} + {{#link-to 'protected.users.edit' model.id class="button-gray smaller"}} + Edit + {{/link-to}} + {{/if}} +
+
diff --git a/app/pods/protected/users/user-form/component.js b/app/pods/protected/users/user-form/component.js new file mode 100644 index 0000000..d5ce463 --- /dev/null +++ b/app/pods/protected/users/user-form/component.js @@ -0,0 +1,19 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + isAdmin: Ember.computed('currentUser', function() { + return this.get('currentUser.role') == 'A'; + }), + + roles: Ember.String.w('A R W'), + + actions: { + save: function() { + this.sendAction('save'); + }, + + cancel: function() { + this.sendAction('cancel'); + }, + } +}); diff --git a/app/pods/protected/users/user-form/template.hbs b/app/pods/protected/users/user-form/template.hbs new file mode 100644 index 0000000..a872aae --- /dev/null +++ b/app/pods/protected/users/user-form/template.hbs @@ -0,0 +1,40 @@ + +
+ {{user.name}} +
+
+ + {{input value=user.name}} +
+
+
+
+ + {{input value=user.email}} +
+
+
+
+ + {{#if isAdmin}} + + {{else}} + {{user.role}} + {{/if}} +
+
+
+
+ + Cancel + + {{#if user.hasDirtyAttributes}} + + {{/if}} + diff --git a/app/router.js b/app/router.js index 5f48eec..3b3655a 100644 --- a/app/router.js +++ b/app/router.js @@ -22,6 +22,7 @@ Router.map(function() { this.route('users', function() { this.route('show', { path: ':user_id' }); this.route('edit', { path: ':user_id/edit' }); + this.route('changepassword', { path: ':user_id/changepassword' }); }); this.route('compare', function() { diff --git a/bower.json b/bower.json index 4161c5e..96af48e 100644 --- a/bower.json +++ b/bower.json @@ -2,10 +2,10 @@ "name": "clostridiumdotinfo", "dependencies": { "jquery": "~2.1.1", - "ember": "1.13.7", + "ember": "1.13.10", "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3", "ember-cli-test-loader": "ember-cli-test-loader#0.1.3", - "ember-data": "1.13.8", + "ember-data": "1.13.13", "ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5", "ember-qunit": "0.4.9", "ember-qunit-notifications": "0.0.7", diff --git a/package.json b/package.json index 10a8182..46f732c 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "ember-cli-release": "0.2.3", "ember-cli-sri": "^1.0.3", "ember-cli-uglify": "^1.2.0", - "ember-data": "1.13.8", + "ember-data": "1.13.13", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.3", "ember-select-2": "1.3.0"