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}}
- |
{{/if}}
{{else}}
@@ -38,6 +44,7 @@
Edit
+ {{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}}
+
+
+ Add characteristic
+
+
+{{/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 @@
+
+
+
+
+
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 @@
+
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"