From b40a7198942c5b016a9a8eccd7f018ad8707e5f2 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 5 Dec 2017 00:08:58 -0600 Subject: [PATCH 01/46] Add preliminary calendar implementation Obviously this has a long way to go! --- app/components/calendar-day.js | 18 ++ app/controllers/calendar.js | 7 + app/models/slot.js | 7 + app/router.js | 2 + app/routes/calendar.js | 11 ++ app/styles/app.scss | 1 + app/templates/calendar.hbs | 7 + app/templates/components/calendar-day.hbs | 7 + mirage/config.js | 2 + mirage/models/slot.js | 4 + package-lock.json | 191 ++++++++++++++++++++++ package.json | 1 + tests/acceptance/calendar-test.js | 52 ++++++ tests/helpers/start-app.js | 2 + tests/pages/calendar.js | 27 +++ 15 files changed, 339 insertions(+) create mode 100644 app/components/calendar-day.js create mode 100644 app/controllers/calendar.js create mode 100644 app/models/slot.js create mode 100644 app/routes/calendar.js create mode 100644 app/templates/calendar.hbs create mode 100644 app/templates/components/calendar-day.hbs create mode 100644 mirage/models/slot.js create mode 100644 tests/acceptance/calendar-test.js create mode 100644 tests/pages/calendar.js diff --git a/app/components/calendar-day.js b/app/components/calendar-day.js new file mode 100644 index 00000000..1f659b52 --- /dev/null +++ b/app/components/calendar-day.js @@ -0,0 +1,18 @@ +import Component from '@ember/component'; +import { computed } from '@ember/object'; + +export default Component.extend({ + daySlots: computed('day.id', 'slots.@each.start', function() { + const dayDateString = this.get('day.date').toDateString(); + const slots = this.get('slots'); + + return slots.filter(slot => dayDateString === slot.get('start').toDateString()).sortBy('start'); + }), + + slot: computed('day.id', 'slots.@each.start', function() { + const dayDateString = this.get('day.date').toDateString(); + const slots = this.get('slots'); + + return slots.find(slot => dayDateString === slot.get('start').toDateString()); + }) +}); diff --git a/app/controllers/calendar.js b/app/controllers/calendar.js new file mode 100644 index 00000000..bbbd7ef9 --- /dev/null +++ b/app/controllers/calendar.js @@ -0,0 +1,7 @@ +import Controller from '@ember/controller'; + +import { alias } from '@ember/object/computed'; + +export default Controller.extend({ + slots: alias('model') +}); diff --git a/app/models/slot.js b/app/models/slot.js new file mode 100644 index 00000000..a3bfbfc2 --- /dev/null +++ b/app/models/slot.js @@ -0,0 +1,7 @@ +import DS from 'ember-data'; + +export default DS.Model.extend({ + start: DS.attr('date'), + end: DS.attr('date'), + count: DS.attr('number') +}); diff --git a/app/router.js b/app/router.js index f7459d4d..5c492fdf 100644 --- a/app/router.js +++ b/app/router.js @@ -27,6 +27,8 @@ Router.map(function() { this.route('login'); this.route('register'); + + this.route('calendar'); }); export default Router; diff --git a/app/routes/calendar.js b/app/routes/calendar.js new file mode 100644 index 00000000..2c8d0d11 --- /dev/null +++ b/app/routes/calendar.js @@ -0,0 +1,11 @@ +import Route from '@ember/routing/route'; + +export default Route.extend({ + model() { + return this.store.findAll('slot').catch(() => [ + this.store.createRecord('slot', {start: new Date(2017, 11, 3, 17), end: new Date(2017, 11, 3, 21), count: 2}), + this.store.createRecord('slot', {start: new Date(2017, 11, 3, 11), end: new Date(2017, 11, 3, 17), count: 3}), + this.store.createRecord('slot', {start: new Date(2017, 11, 8, 17), count: 4}) + ]); + } +}); diff --git a/app/styles/app.scss b/app/styles/app.scss index baf4f6ca..4080ca31 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -4,6 +4,7 @@ $primary: 'indigo'; @import 'ember-paper'; @import 'paper-data-table'; +@import 'ember-power-calendar'; @import 'loading'; diff --git a/app/templates/calendar.hbs b/app/templates/calendar.hbs new file mode 100644 index 00000000..74b3fae7 --- /dev/null +++ b/app/templates/calendar.hbs @@ -0,0 +1,7 @@ +{{#power-calendar as |calendar|}} + {{calendar.nav}} + + {{#calendar.days showDaysAround=false as |day|}} + {{calendar-day day=day slots=slots}} + {{/calendar.days}} +{{/power-calendar}} diff --git a/app/templates/components/calendar-day.hbs b/app/templates/components/calendar-day.hbs new file mode 100644 index 00000000..95827f1b --- /dev/null +++ b/app/templates/components/calendar-day.hbs @@ -0,0 +1,7 @@ +{{day.number}} + +{{#each daySlots as |slot|}} +
+ {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}}: {{slot.count}} +
+{{/each}} diff --git a/mirage/config.js b/mirage/config.js index 9a657e8b..7209413d 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -44,4 +44,6 @@ export default function() { this.get('/users/current', ({ users }) => { return users.first(); }); + + this.get('/slots'); } diff --git a/mirage/models/slot.js b/mirage/models/slot.js new file mode 100644 index 00000000..1486a724 --- /dev/null +++ b/mirage/models/slot.js @@ -0,0 +1,4 @@ +import { Model } from 'ember-cli-mirage'; + +export default Model.extend({ +}); diff --git a/package-lock.json b/package-lock.json index 97c4f5d6..335332db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4160,6 +4160,15 @@ "ember-cli-babel": "6.8.2" } }, + "ember-assign-helper": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ember-assign-helper/-/ember-assign-helper-0.1.2.tgz", + "integrity": "sha1-PR1XXz1EV7NmKyFNTG5nG9RiytA=", + "dev": true, + "requires": { + "ember-cli-babel": "6.8.2" + } + }, "ember-basic-dropdown": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/ember-basic-dropdown/-/ember-basic-dropdown-0.33.5.tgz", @@ -10220,6 +10229,166 @@ } } }, + "ember-power-calendar": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/ember-power-calendar/-/ember-power-calendar-0.6.2.tgz", + "integrity": "sha512-sbY/Nx1F7LRKxXoLXqphJE2EafPySf5zglRr2IhLCSgrOGpmgITN85hX4lYrw/NYTLnVlibVAf/YJKa1vx51vg==", + "dev": true, + "requires": { + "ember-assign-helper": "0.1.2", + "ember-cli-babel": "6.10.0", + "ember-cli-htmlbars": "2.0.3", + "ember-cli-moment-shim": "3.5.0", + "ember-concurrency": "0.8.12", + "ember-moment": "7.5.0", + "ember-native-dom-helpers": "0.5.4" + }, + "dependencies": { + "broccoli-merge-trees": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz", + "integrity": "sha1-EK6kbdXOvMi499WlTwqEpPC7kLk=", + "dev": true, + "requires": { + "broccoli-plugin": "1.3.0", + "merge-trees": "1.0.1" + } + }, + "ember-cli-babel": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.10.0.tgz", + "integrity": "sha512-MbgXmePweFzjkpN0l2eYFIU6XKfEKCaAx4Xk9wdL3vsPAvAm4N0DXnz4pOQ3OLezhl0bJJvutD3uLQ7Eo3sSTA==", + "dev": true, + "requires": { + "amd-name-resolver": "0.0.7", + "babel-plugin-debug-macros": "0.1.11", + "babel-plugin-ember-modules-api-polyfill": "2.0.1", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-polyfill": "6.26.0", + "babel-preset-env": "1.6.0", + "broccoli-babel-transpiler": "6.1.2", + "broccoli-debug": "0.6.3", + "broccoli-funnel": "1.2.0", + "broccoli-source": "1.1.0", + "clone": "2.1.1", + "ember-cli-version-checker": "2.1.0", + "semver": "5.4.1" + } + }, + "ember-cli-moment-shim": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ember-cli-moment-shim/-/ember-cli-moment-shim-3.5.0.tgz", + "integrity": "sha1-fqjUKwoEx2clgoezBEdoHlL7oMQ=", + "dev": true, + "requires": { + "broccoli-funnel": "2.0.1", + "broccoli-merge-trees": "2.0.0", + "broccoli-source": "1.1.0", + "broccoli-stew": "1.5.0", + "chalk": "1.1.3", + "ember-cli-babel": "6.10.0", + "ember-cli-import-polyfill": "0.2.0", + "exists-sync": "0.0.4", + "lodash.defaults": "4.2.0", + "moment": "2.18.1", + "moment-timezone": "0.5.13" + }, + "dependencies": { + "broccoli-funnel": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz", + "integrity": "sha512-C8Lnp9TVsSSiZMGEF16C0dCiNg2oJqUKwuZ1K4kVC6qRPG/2Cj/rtB5kRCC9qEbwqhX71bDbfHROx0L3J7zXQg==", + "dev": true, + "requires": { + "array-equal": "1.0.0", + "blank-object": "1.0.2", + "broccoli-plugin": "1.3.0", + "debug": "2.6.8", + "fast-ordered-set": "1.0.3", + "fs-tree-diff": "0.5.6", + "heimdalljs": "0.2.5", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "path-posix": "1.0.0", + "rimraf": "2.6.1", + "symlink-or-copy": "1.1.8", + "walk-sync": "0.3.2" + } + } + } + }, + "ember-cli-version-checker": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.1.0.tgz", + "integrity": "sha512-ssiNyVTp+PphroFum8guHX9py4xU1PCxkRYgb25NxumgjpKTPjhkgTfpRRKXlIQe+/wVMmhf+Uv6w9vSLZKWKQ==", + "dev": true, + "requires": { + "resolve": "1.4.0", + "semver": "5.4.1" + } + }, + "ember-concurrency": { + "version": "0.8.12", + "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-0.8.12.tgz", + "integrity": "sha1-+5EYDl7+sQJM+iz7mdL+ZyGTDJE=", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "ember-cli-babel": "6.10.0", + "ember-getowner-polyfill": "2.2.0", + "ember-maybe-import-regenerator": "0.1.6" + } + }, + "ember-factory-for-polyfill": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ember-factory-for-polyfill/-/ember-factory-for-polyfill-1.3.1.tgz", + "integrity": "sha512-y3iG2iCzH96lZMTWQw6LWNLAfOmDC4pXKbZP6FxG8lt7GGaNFkZjwsf+Z5GAe7kxfD7UG4lVkF7x37K82rySGA==", + "dev": true, + "requires": { + "ember-cli-version-checker": "2.1.0" + } + }, + "ember-getowner-polyfill": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ember-getowner-polyfill/-/ember-getowner-polyfill-2.2.0.tgz", + "integrity": "sha512-rwGMJgbGzxIAiWYjdpAh04Abvt0s3HuS/VjHzUFhVyVg2pzAuz45B9AzOxYXzkp88vFC7FPaiA4kE8NxNk4A4Q==", + "dev": true, + "requires": { + "ember-cli-version-checker": "2.1.0", + "ember-factory-for-polyfill": "1.3.1" + } + }, + "ember-macro-helpers": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/ember-macro-helpers/-/ember-macro-helpers-0.17.0.tgz", + "integrity": "sha1-XmSkn0duOMGRav91+UlFVTPNGr4=", + "dev": true, + "requires": { + "ember-cli-babel": "6.10.0", + "ember-cli-string-utils": "1.1.0", + "ember-cli-test-info": "1.0.0", + "ember-weakmap": "3.1.1" + } + }, + "ember-moment": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/ember-moment/-/ember-moment-7.5.0.tgz", + "integrity": "sha1-ntJbMq6UGy8dkRbET1GKUr2wFyI=", + "dev": true, + "requires": { + "ember-cli-babel": "6.10.0", + "ember-getowner-polyfill": "2.2.0", + "ember-macro-helpers": "0.17.0" + } + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "dev": true + } + } + }, "ember-power-select": { "version": "1.9.6", "resolved": "https://registry.npmjs.org/ember-power-select/-/ember-power-select-1.9.6.tgz", @@ -11305,6 +11474,28 @@ "semver": "5.4.1" } }, + "ember-weakmap": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/ember-weakmap/-/ember-weakmap-3.1.1.tgz", + "integrity": "sha512-rfW3A1m3NFsHd/NuHyBkssU0Qf0zGcJmASGfhjZc7fIQeBZvSLIFYZTej+W+YBLPtED9h/SVW63DHTRY5PUR4Q==", + "dev": true, + "requires": { + "browserslist": "2.4.0", + "debug": "3.1.0", + "ember-cli-babel": "6.8.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "ember-wormhole": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/ember-wormhole/-/ember-wormhole-0.5.2.tgz", diff --git a/package.json b/package.json index 78a156e3..b370494f 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "ember-moment": "7.2.0", "ember-paper": "backspace/ember-paper#autocomplete-validation", "ember-phoenix": "^0.1.6", + "ember-power-calendar": "^0.6.2", "ember-resolver": "^4.0.0", "ember-simple-auth": "1.2.0", "ember-source": "~2.16.0", diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js new file mode 100644 index 00000000..561b1a7c --- /dev/null +++ b/tests/acceptance/calendar-test.js @@ -0,0 +1,52 @@ +import { test } from 'qunit'; +import moduleForAcceptance from 'prison-rideshare-ui/tests/helpers/module-for-acceptance'; + +import page from 'prison-rideshare-ui/tests/pages/calendar'; + +moduleForAcceptance('Acceptance | calendar', { + beforeEach() { + server.create('slot', { + start: new Date(2017, 11, 4, 17), + end: new Date(2017, 11, 4, 20), + count: 2 + }); + + server.create('slot', { + start: new Date(2017, 11, 10, 17), + end: new Date(2017, 11, 10, 21), + count: 2 + }); + + server.create('slot', { + start: new Date(2017, 11, 10, 11), + end: new Date(2017, 11, 10, 17), + count: 3 + }); + } +}); + +test('visiting /calendar', function(assert) { + page.visit(); + + andThen(function() { + page.days(3).as(d4 => { + assert.equal(d4.slots().count, 1, 'expected one slot on Monday'); + d4.slots(0).as(s1 => { + assert.equal(s1.hours, '5PM–8PM'); + assert.equal(s1.count, '2'); + }) + }); + + page.days(9).as(d10 => { + assert.equal(d10.slots().count, 2, 'expected two slots on Sunday'); + d10.slots(0).as(s1 => { + assert.equal(s1.hours, '11AM–5PM'); + assert.equal(s1.count, '3'); + }); + d10.slots(1).as(s2 => { + assert.equal(s2.hours, '5PM–9PM'); + assert.equal(s2.count, '2'); + }); + }); + }); +}); diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js index f19f1481..e398062f 100644 --- a/tests/helpers/start-app.js +++ b/tests/helpers/start-app.js @@ -4,8 +4,10 @@ import { merge } from '@ember/polyfills'; import { run } from '@ember/runloop'; import registerPowerSelectHelpers from '../../tests/helpers/ember-power-select'; +import registerPowerCalendarHelpers from '../../tests/helpers/ember-power-calendar'; registerPowerSelectHelpers(); +registerPowerCalendarHelpers(); export default function startApp(attrs) { let attributes = merge({}, config.APP); diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js new file mode 100644 index 00000000..b432a6b3 --- /dev/null +++ b/tests/pages/calendar.js @@ -0,0 +1,27 @@ +import { + collection, + create, + text, + visitable +} from 'ember-cli-page-object'; + +export default create({ + visit: visitable('/calendar'), + + month: text('something'), + + days: collection({ + itemScope: '.ember-power-calendar-day', + + item: { + slots: collection({ + itemScope: '.slot', + + item: { + hours: text('.hours'), + count: text('.count') + } + }) + } + }) +}); From cfc02baf35bf1530cb3e6789121bc337ae69406e Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 10 Dec 2017 11:29:09 -0600 Subject: [PATCH 02/46] Add preliminary display of commitments --- app/models/commitment.js | 5 +++++ app/models/slot.js | 4 +++- app/styles/app.scss | 2 ++ app/styles/calendar.scss | 5 +++++ app/templates/components/calendar-day.hbs | 2 +- mirage/models/commitment.js | 5 +++++ mirage/models/slot.js | 3 ++- mirage/serializers/slot.js | 5 +++++ tests/acceptance/calendar-test.js | 10 ++++++++-- tests/pages/calendar.js | 5 ++++- 10 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 app/models/commitment.js create mode 100644 app/styles/calendar.scss create mode 100644 mirage/models/commitment.js create mode 100644 mirage/serializers/slot.js diff --git a/app/models/commitment.js b/app/models/commitment.js new file mode 100644 index 00000000..4d7678dc --- /dev/null +++ b/app/models/commitment.js @@ -0,0 +1,5 @@ +import DS from 'ember-data'; + +export default DS.Model.extend({ + slot: DS.belongsTo({ async: false }) +}); diff --git a/app/models/slot.js b/app/models/slot.js index a3bfbfc2..3d66319a 100644 --- a/app/models/slot.js +++ b/app/models/slot.js @@ -3,5 +3,7 @@ import DS from 'ember-data'; export default DS.Model.extend({ start: DS.attr('date'), end: DS.attr('date'), - count: DS.attr('number') + count: DS.attr('number'), + + commitments: DS.hasMany({ async: false }) }); diff --git a/app/styles/app.scss b/app/styles/app.scss index 4080ca31..8edf522b 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -8,6 +8,8 @@ $primary: 'indigo'; @import 'loading'; +@import 'calendar'; + body { max-width: 100%; max-height: 100%; diff --git a/app/styles/calendar.scss b/app/styles/calendar.scss new file mode 100644 index 00000000..60e440d2 --- /dev/null +++ b/app/styles/calendar.scss @@ -0,0 +1,5 @@ +.slot { + &.is-committed-to { + background: blue; + } +} diff --git a/app/templates/components/calendar-day.hbs b/app/templates/components/calendar-day.hbs index 95827f1b..8038c862 100644 --- a/app/templates/components/calendar-day.hbs +++ b/app/templates/components/calendar-day.hbs @@ -1,7 +1,7 @@ {{day.number}} {{#each daySlots as |slot|}} -
+
{{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}}: {{slot.count}}
{{/each}} diff --git a/mirage/models/commitment.js b/mirage/models/commitment.js new file mode 100644 index 00000000..860b5ee9 --- /dev/null +++ b/mirage/models/commitment.js @@ -0,0 +1,5 @@ +import { Model, belongsTo } from 'ember-cli-mirage'; + +export default Model.extend({ + slot: belongsTo() +}); diff --git a/mirage/models/slot.js b/mirage/models/slot.js index 1486a724..5189f662 100644 --- a/mirage/models/slot.js +++ b/mirage/models/slot.js @@ -1,4 +1,5 @@ -import { Model } from 'ember-cli-mirage'; +import { Model, hasMany } from 'ember-cli-mirage'; export default Model.extend({ + commitments: hasMany() }); diff --git a/mirage/serializers/slot.js b/mirage/serializers/slot.js new file mode 100644 index 00000000..a2edf62a --- /dev/null +++ b/mirage/serializers/slot.js @@ -0,0 +1,5 @@ +import { JSONAPISerializer } from 'ember-cli-mirage'; + +export default JSONAPISerializer.extend({ + include: ['commitments'] +}); diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 561b1a7c..09d0c95b 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -5,7 +5,7 @@ import page from 'prison-rideshare-ui/tests/pages/calendar'; moduleForAcceptance('Acceptance | calendar', { beforeEach() { - server.create('slot', { + const committedSlot = server.create('slot', { start: new Date(2017, 11, 4, 17), end: new Date(2017, 11, 4, 20), count: 2 @@ -22,10 +22,14 @@ moduleForAcceptance('Acceptance | calendar', { end: new Date(2017, 11, 10, 17), count: 3 }); + + committedSlot.createCommitment({ + + }); } }); -test('visiting /calendar', function(assert) { +test('calendar shows existing commitments', function(assert) { page.visit(); andThen(function() { @@ -34,6 +38,7 @@ test('visiting /calendar', function(assert) { d4.slots(0).as(s1 => { assert.equal(s1.hours, '5PM–8PM'); assert.equal(s1.count, '2'); + assert.ok(s1.isCommittedTo, 'expected the slot to be committed-to'); }) }); @@ -42,6 +47,7 @@ test('visiting /calendar', function(assert) { d10.slots(0).as(s1 => { assert.equal(s1.hours, '11AM–5PM'); assert.equal(s1.count, '3'); + assert.notOk(s1.isCommittedTo, 'expected the slot to not be committed-to'); }); d10.slots(1).as(s2 => { assert.equal(s2.hours, '5PM–9PM'); diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index b432a6b3..9692ff35 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -1,6 +1,7 @@ import { collection, create, + hasClass, text, visitable } from 'ember-cli-page-object'; @@ -19,7 +20,9 @@ export default create({ item: { hours: text('.hours'), - count: text('.count') + count: text('.count'), + + isCommittedTo: hasClass('is-committed-to') } }) } From 7bef97c59bcbcfa0acaff30a986d3cd3a72b4cc2 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 10 Dec 2017 12:06:48 -0600 Subject: [PATCH 03/46] Add ability to delete commitments --- app/components/calendar-days.js | 3 +++ app/components/calendar-slot.js | 7 ++++++ app/templates/calendar.hbs | 2 +- app/templates/components/calendar-day.hbs | 4 +--- app/templates/components/calendar-days.hbs | 28 ++++++++++++++++++++++ app/templates/components/calendar-slot.hbs | 3 +++ mirage/config.js | 1 + tests/acceptance/calendar-test.js | 9 ++++++- 8 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 app/components/calendar-days.js create mode 100644 app/components/calendar-slot.js create mode 100644 app/templates/components/calendar-days.hbs create mode 100644 app/templates/components/calendar-slot.hbs diff --git a/app/components/calendar-days.js b/app/components/calendar-days.js new file mode 100644 index 00000000..b24e4aa3 --- /dev/null +++ b/app/components/calendar-days.js @@ -0,0 +1,3 @@ +import Days from 'ember-power-calendar/components/power-calendar/days'; + +export default Days; diff --git a/app/components/calendar-slot.js b/app/components/calendar-slot.js new file mode 100644 index 00000000..fc12f2a1 --- /dev/null +++ b/app/components/calendar-slot.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; + +export default Component.extend({ + click() { + this.get('slot.commitments.firstObject').destroyRecord(); + } +}); diff --git a/app/templates/calendar.hbs b/app/templates/calendar.hbs index 74b3fae7..6d87b399 100644 --- a/app/templates/calendar.hbs +++ b/app/templates/calendar.hbs @@ -1,4 +1,4 @@ -{{#power-calendar as |calendar|}} +{{#power-calendar daysComponent='calendar-days' as |calendar|}} {{calendar.nav}} {{#calendar.days showDaysAround=false as |day|}} diff --git a/app/templates/components/calendar-day.hbs b/app/templates/components/calendar-day.hbs index 8038c862..bac521db 100644 --- a/app/templates/components/calendar-day.hbs +++ b/app/templates/components/calendar-day.hbs @@ -1,7 +1,5 @@ {{day.number}} {{#each daySlots as |slot|}} -
- {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}}: {{slot.count}} -
+ {{calendar-slot slot=slot}} {{/each}} diff --git a/app/templates/components/calendar-days.hbs b/app/templates/components/calendar-days.hbs new file mode 100644 index 00000000..33d1a918 --- /dev/null +++ b/app/templates/components/calendar-days.hbs @@ -0,0 +1,28 @@ +{{! FIXME it’s too bad I have to copy the entire template just to change the days to divs instead of buttons! }} +
+ {{#each weekdaysNames as |wdn|}} +
{{wdn}}
+ {{/each}} +
+ +
+ {{#each weeks key='id' as |week|}} +
+ {{#each week.days key='id' as |day|}} +
+ {{#if hasBlock}} + {{yield day publicAPI}} + {{else}} + {{day.number}} + {{/if}} +
+ {{/each}} +
+ {{/each}} +
diff --git a/app/templates/components/calendar-slot.hbs b/app/templates/components/calendar-slot.hbs new file mode 100644 index 00000000..3963a88b --- /dev/null +++ b/app/templates/components/calendar-slot.hbs @@ -0,0 +1,3 @@ +
+ {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}}: {{slot.count}} +
diff --git a/mirage/config.js b/mirage/config.js index 7209413d..5c7db9aa 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -46,4 +46,5 @@ export default function() { }); this.get('/slots'); + this.delete('/commitments/:id'); } diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 09d0c95b..6b01903d 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -29,7 +29,7 @@ moduleForAcceptance('Acceptance | calendar', { } }); -test('calendar shows existing commitments', function(assert) { +test('calendar shows existing commitments and lets them be changed', function(assert) { page.visit(); andThen(function() { @@ -55,4 +55,11 @@ test('calendar shows existing commitments', function(assert) { }); }); }); + + page.days(3).slots(0).click(); + + andThen(() => { + assert.notOk(page.days(3).slots(0).isCommittedTo, 'expected the slot to not longer be committed-to'); + assert.equal(server.db.commitments.length, 0, 'expected the commitment to have been deleted on the server'); + }); }); From 8b3f7b2a9e196da592a5bfbd3e3e354be842694c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 10 Dec 2017 12:34:15 -0600 Subject: [PATCH 04/46] Add ability to commit to a slot --- app/components/calendar-slot.js | 18 +++++++++++++++++- mirage/config.js | 1 + tests/acceptance/calendar-test.js | 11 ++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/app/components/calendar-slot.js b/app/components/calendar-slot.js index fc12f2a1..7bd6e3a7 100644 --- a/app/components/calendar-slot.js +++ b/app/components/calendar-slot.js @@ -1,7 +1,23 @@ import Component from '@ember/component'; +import { computed } from '@ember/object'; +import { inject as service } from '@ember/service'; export default Component.extend({ + store: service(), + + isCommittedTo: computed('slot.commitments.length', function() { + if (this.get('slot.commitments.length')) { + return true; + } else { + return false; + } + }), + click() { - this.get('slot.commitments.firstObject').destroyRecord(); + if (this.get('isCommittedTo')) { + this.get('slot.commitments.firstObject').destroyRecord(); + } else { + this.get('store').createRecord('commitment', { slot: this.get('slot') }).save(); + } } }); diff --git a/mirage/config.js b/mirage/config.js index 5c7db9aa..0c61b6e3 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -46,5 +46,6 @@ export default function() { }); this.get('/slots'); + this.post('/commitments'); this.delete('/commitments/:id'); } diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 6b01903d..7ab4a698 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -11,7 +11,7 @@ moduleForAcceptance('Acceptance | calendar', { count: 2 }); - server.create('slot', { + this.toCommitSlot = server.create('slot', { start: new Date(2017, 11, 10, 17), end: new Date(2017, 11, 10, 21), count: 2 @@ -62,4 +62,13 @@ test('calendar shows existing commitments and lets them be changed', function(as assert.notOk(page.days(3).slots(0).isCommittedTo, 'expected the slot to not longer be committed-to'); assert.equal(server.db.commitments.length, 0, 'expected the commitment to have been deleted on the server'); }); + + page.days(9).slots(1).click(); + + andThen(() => { + assert.ok(page.days(9).slots(1).isCommittedTo, 'expected the slot to be newly committed-to'); + + const [commitment] = server.db.commitments; + assert.equal(commitment.slotId, this.toCommitSlot.id, 'expected the server to have the newly-created commitment'); + }); }); From 570b3bbc131c6679c257fd05c79ab033236ec8f3 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 20 Dec 2017 15:53:47 -0600 Subject: [PATCH 05/46] Add step toward token requirement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This doesn’t actually work, though it did in the development environment… 🤔 --- app/adapters/commitment.js | 5 +++++ app/authorizers/commitment.js | 12 ++++++++++++ mirage/config.js | 12 +++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 app/adapters/commitment.js create mode 100644 app/authorizers/commitment.js diff --git a/app/adapters/commitment.js b/app/adapters/commitment.js new file mode 100644 index 00000000..2a163a05 --- /dev/null +++ b/app/adapters/commitment.js @@ -0,0 +1,5 @@ +import ApplicationAdapter from './application'; + +export default ApplicationAdapter.extend({ + authorizer: 'authorizer:commitment' +}); diff --git a/app/authorizers/commitment.js b/app/authorizers/commitment.js new file mode 100644 index 00000000..1d20c213 --- /dev/null +++ b/app/authorizers/commitment.js @@ -0,0 +1,12 @@ +import OAuth2Bearer from 'ember-simple-auth/authorizers/oauth2-bearer'; +import { isEmpty } from '@ember/utils'; + +export default OAuth2Bearer.extend({ + authorize(data, block) { + const accessToken = 'XXX'; + + if (!isEmpty(accessToken)) { + block('Authorization', `Person Bearer ${accessToken}`); + } + } +}); diff --git a/mirage/config.js b/mirage/config.js index 0c61b6e3..d0c46e95 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -1,4 +1,5 @@ import config from 'prison-rideshare-ui/config/environment'; +import Mirage from 'ember-cli-mirage'; export default function() { this.passthrough('/write-coverage'); @@ -46,6 +47,15 @@ export default function() { }); this.get('/slots'); - this.post('/commitments'); + + this.post('/commitments', (db, request) => { + console.log('request?', request); + if (request.requestHeaders.Authorization === 'Person Bearer XXX') { + return db.commitments; + } else { + return new Mirage.Response(401, {}, {}); + } + }); + this.delete('/commitments/:id'); } From 1a34e206b066bd314dc5aec63d2fdca4ccb78c1a Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 20 Dec 2017 18:04:50 -0600 Subject: [PATCH 06/46] Correct commitment-creation with token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This still needs token-getting etc, but it’s progress! --- mirage/config.js | 6 +++--- tests/acceptance/calendar-test.js | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mirage/config.js b/mirage/config.js index d0c46e95..b2f1ba74 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -48,10 +48,10 @@ export default function() { this.get('/slots'); - this.post('/commitments', (db, request) => { - console.log('request?', request); + this.post('/commitments', function({ commitments }, request) { if (request.requestHeaders.Authorization === 'Person Bearer XXX') { - return db.commitments; + const attrs = this.normalizedRequestAttrs(); + return commitments.create(attrs); } else { return new Mirage.Response(401, {}, {}); } diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 7ab4a698..746844ab 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -1,6 +1,8 @@ import { test } from 'qunit'; import moduleForAcceptance from 'prison-rideshare-ui/tests/helpers/module-for-acceptance'; +import { authenticateSession } from 'prison-rideshare-ui/tests/helpers/ember-simple-auth'; + import page from 'prison-rideshare-ui/tests/pages/calendar'; moduleForAcceptance('Acceptance | calendar', { @@ -26,6 +28,9 @@ moduleForAcceptance('Acceptance | calendar', { committedSlot.createCommitment({ }); + + // FIXME without this, the Person Bearer isn’t sent by the authoriser… ya + authenticateSession(this.application); } }); From aef544bcfb48c7dc72417ea5daaaec403e9360cf Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 20 Dec 2017 19:22:51 -0600 Subject: [PATCH 07/46] Add progress toward magic token exchange --- app/authenticators/commitment.js | 49 +++++++++++++++++++++++++++++++ app/authorizers/commitment.js | 3 +- app/routes/calendar.js | 23 +++++++++++---- mirage/config.js | 28 ++++++++++++++++++ tests/acceptance/calendar-test.js | 2 +- 5 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 app/authenticators/commitment.js diff --git a/app/authenticators/commitment.js b/app/authenticators/commitment.js new file mode 100644 index 00000000..0e878795 --- /dev/null +++ b/app/authenticators/commitment.js @@ -0,0 +1,49 @@ +import Ember from 'ember'; + +import OAuth2PasswordGrant from 'ember-simple-auth/authenticators/oauth2-password-grant'; +import config from 'prison-rideshare-ui/config/environment'; + +import RSVP from 'rsvp'; +import { makeArray } from '@ember/array'; +import { isEmpty } from '@ember/utils'; +import { run } from '@ember/runloop'; +import { + merge, + assign as emberAssign +} from '@ember/polyfills'; + +const assign = emberAssign || merge; + +export default OAuth2PasswordGrant.extend({ + serverTokenEndpoint: `${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace}/people/token`, + + // FIXME this is overkill maybe??? + authenticate(magicToken, scope = [], headers = {}) { + return new RSVP.Promise((resolve, reject) => { + const data = { 'grant_type': 'magic', token: magicToken }; + const serverTokenEndpoint = this.get('serverTokenEndpoint'); + const useResponse = this.get('rejectWithResponse'); + const scopesString = makeArray(scope).join(' '); + if (!isEmpty(scopesString)) { + data.scope = scopesString; + } + this.makeRequest(serverTokenEndpoint, data, headers).then((response) => { + run(() => { + if (!this._validate(response)) { + reject('access_token is missing in server response'); + } + + const expiresAt = this._absolutizeExpirationTime(response['expires_in']); + this._scheduleAccessTokenRefresh(response['expires_in'], expiresAt, response['refresh_token']); + if (!isEmpty(expiresAt)) { + response = assign(response, { 'expires_at': expiresAt }); + } + + resolve(response); + }); + }, (response) => { + run(null, reject, useResponse ? response : (response.responseJSON || response.responseText)); + }); + }); + }, +}); diff --git a/app/authorizers/commitment.js b/app/authorizers/commitment.js index 1d20c213..18648255 100644 --- a/app/authorizers/commitment.js +++ b/app/authorizers/commitment.js @@ -3,7 +3,8 @@ import { isEmpty } from '@ember/utils'; export default OAuth2Bearer.extend({ authorize(data, block) { - const accessToken = 'XXX'; + // FIXME what if the access token is for the application authenticator??? + const accessToken = data['access_token']; if (!isEmpty(accessToken)) { block('Authorization', `Person Bearer ${accessToken}`); diff --git a/app/routes/calendar.js b/app/routes/calendar.js index 2c8d0d11..ac02a3a2 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -1,11 +1,22 @@ import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; export default Route.extend({ - model() { - return this.store.findAll('slot').catch(() => [ - this.store.createRecord('slot', {start: new Date(2017, 11, 3, 17), end: new Date(2017, 11, 3, 21), count: 2}), - this.store.createRecord('slot', {start: new Date(2017, 11, 3, 11), end: new Date(2017, 11, 3, 17), count: 3}), - this.store.createRecord('slot', {start: new Date(2017, 11, 8, 17), count: 4}) - ]); + session: service(), + + // FIXME is it possible to get the token from elsewhere than the transition object? + model(params, { queryParams }) { + return this.get('session').authenticate( + 'authenticator:commitment', + queryParams.token + ).catch(error => { + this.set('error', error); + }).then(() => { + return this.store.findAll('slot').catch(() => [ + this.store.createRecord('slot', {start: new Date(2017, 11, 3, 17), end: new Date(2017, 11, 3, 21), count: 2}), + this.store.createRecord('slot', {start: new Date(2017, 11, 3, 11), end: new Date(2017, 11, 3, 17), count: 3}), + this.store.createRecord('slot', {start: new Date(2017, 11, 8, 17), count: 4}) + ]); + }); } }); diff --git a/mirage/config.js b/mirage/config.js index b2f1ba74..a39a2d08 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -58,4 +58,32 @@ export default function() { }); this.delete('/commitments/:id'); + + this.post('/people/token', function(db, { requestBody }) { + const bodyParams = parseQueryString(requestBody); + + if (bodyParams.grant_type === 'magic' && bodyParams.token === 'MAGICTOKEN') { + return { + access_token: 'XXX' + }; + } else { + return new Mirage.Response(401, {}, {}); + } + }); +} + +// Taken from https://gist.github.com/Manc/9409355 + +function parseQueryString(query) { + var obj = {}, + qPos = query.indexOf("?"), + tokens = query.substr(qPos + 1).split('&'), + i = tokens.length - 1; + if (qPos !== -1 || query.indexOf("=") !== -1) { + for (; i >= 0; i--) { + var s = tokens[i].split('='); + obj[unescape(s[0])] = s.hasOwnProperty(1) ? unescape(s[1]) : null; + } + } + return obj; } diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 746844ab..c14fd39b 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -35,7 +35,7 @@ moduleForAcceptance('Acceptance | calendar', { }); test('calendar shows existing commitments and lets them be changed', function(assert) { - page.visit(); + page.visit({ token: 'MAGICTOKEN' }); andThen(function() { page.days(3).as(d4 => { From 23ef370f7e26f5fe917465de94be4c68534c4eb4 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 21 Dec 2017 15:57:54 -0600 Subject: [PATCH 08/46] Update slot assertions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maybe this is subpar in this case 🤔 --- tests/acceptance/calendar-test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index c14fd39b..6eeca611 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -41,7 +41,7 @@ test('calendar shows existing commitments and lets them be changed', function(as page.days(3).as(d4 => { assert.equal(d4.slots().count, 1, 'expected one slot on Monday'); d4.slots(0).as(s1 => { - assert.equal(s1.hours, '5PM–8PM'); + assert.equal(s1.hours, '5P–8P'); assert.equal(s1.count, '2'); assert.ok(s1.isCommittedTo, 'expected the slot to be committed-to'); }) @@ -50,12 +50,12 @@ test('calendar shows existing commitments and lets them be changed', function(as page.days(9).as(d10 => { assert.equal(d10.slots().count, 2, 'expected two slots on Sunday'); d10.slots(0).as(s1 => { - assert.equal(s1.hours, '11AM–5PM'); + assert.equal(s1.hours, '11A–5P'); assert.equal(s1.count, '3'); assert.notOk(s1.isCommittedTo, 'expected the slot to not be committed-to'); }); d10.slots(1).as(s2 => { - assert.equal(s2.hours, '5PM–9PM'); + assert.equal(s2.hours, '5P–9P'); assert.equal(s2.count, '2'); }); }); From e3bf69f85e09639640d8e0f132c6be539d7161a3 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 21 Dec 2017 16:11:34 -0600 Subject: [PATCH 09/46] Update Ember Power Calendar --- package-lock.json | 60 +++++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5383ea1a..55550b36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10044,20 +10044,29 @@ } }, "ember-power-calendar": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/ember-power-calendar/-/ember-power-calendar-0.6.2.tgz", - "integrity": "sha512-sbY/Nx1F7LRKxXoLXqphJE2EafPySf5zglRr2IhLCSgrOGpmgITN85hX4lYrw/NYTLnVlibVAf/YJKa1vx51vg==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ember-power-calendar/-/ember-power-calendar-0.7.1.tgz", + "integrity": "sha512-3tlUpDE6Uv+xPqhMqefFABwhMSnalLG3Q+OKIQnKHnSiwFFAdldrgQzH7uv5734mgTPW5uX9C6Kp05aMDAoSHA==", "dev": true, "requires": { "ember-assign-helper": "0.1.2", - "ember-cli-babel": "6.10.0", + "ember-cli-babel": "6.11.0", "ember-cli-htmlbars": "2.0.3", "ember-cli-moment-shim": "3.5.0", "ember-concurrency": "0.8.12", "ember-moment": "7.5.0", - "ember-native-dom-helpers": "0.5.4" + "ember-native-dom-helpers": "0.5.10" }, "dependencies": { + "babel-plugin-ember-modules-api-polyfill": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.0.tgz", + "integrity": "sha512-cv5ZimF5X52uW7Ul83UUxtsFZE6rZYkMv6qWnAeiDLT1/KtpVrTkJpwzDlvJ/FhKJZ43ih4GbFbhuhBKKT7vIw==", + "dev": true, + "requires": { + "ember-rfc176-data": "0.3.1" + } + }, "broccoli-merge-trees": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz", @@ -10069,14 +10078,14 @@ } }, "ember-cli-babel": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.10.0.tgz", - "integrity": "sha512-MbgXmePweFzjkpN0l2eYFIU6XKfEKCaAx4Xk9wdL3vsPAvAm4N0DXnz4pOQ3OLezhl0bJJvutD3uLQ7Eo3sSTA==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.11.0.tgz", + "integrity": "sha512-lHQyl30lbAsMmMq2it1GO85HKrqr2gMpK5CFxmOgTJ3moBqOGMKsdV3Z0qXWpgh8Asy7pB9AACMShdgfQvSGPg==", "dev": true, "requires": { "amd-name-resolver": "0.0.7", "babel-plugin-debug-macros": "0.1.11", - "babel-plugin-ember-modules-api-polyfill": "2.0.1", + "babel-plugin-ember-modules-api-polyfill": "2.3.0", "babel-plugin-transform-es2015-modules-amd": "6.24.1", "babel-polyfill": "6.26.0", "babel-preset-env": "1.6.0", @@ -10100,7 +10109,7 @@ "broccoli-source": "1.1.0", "broccoli-stew": "1.5.0", "chalk": "1.1.3", - "ember-cli-babel": "6.10.0", + "ember-cli-babel": "6.11.0", "ember-cli-import-polyfill": "0.2.0", "exists-sync": "0.0.4", "lodash.defaults": "4.2.0", @@ -10141,27 +10150,6 @@ "semver": "5.4.1" } }, - "ember-concurrency": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-0.8.12.tgz", - "integrity": "sha1-+5EYDl7+sQJM+iz7mdL+ZyGTDJE=", - "dev": true, - "requires": { - "babel-core": "6.26.0", - "ember-cli-babel": "6.10.0", - "ember-getowner-polyfill": "2.2.0", - "ember-maybe-import-regenerator": "0.1.6" - } - }, - "ember-factory-for-polyfill": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ember-factory-for-polyfill/-/ember-factory-for-polyfill-1.3.1.tgz", - "integrity": "sha512-y3iG2iCzH96lZMTWQw6LWNLAfOmDC4pXKbZP6FxG8lt7GGaNFkZjwsf+Z5GAe7kxfD7UG4lVkF7x37K82rySGA==", - "dev": true, - "requires": { - "ember-cli-version-checker": "2.1.0" - } - }, "ember-getowner-polyfill": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ember-getowner-polyfill/-/ember-getowner-polyfill-2.2.0.tgz", @@ -10178,7 +10166,7 @@ "integrity": "sha1-XmSkn0duOMGRav91+UlFVTPNGr4=", "dev": true, "requires": { - "ember-cli-babel": "6.10.0", + "ember-cli-babel": "6.11.0", "ember-cli-string-utils": "1.1.0", "ember-cli-test-info": "1.0.0", "ember-weakmap": "3.1.1" @@ -10190,11 +10178,17 @@ "integrity": "sha1-ntJbMq6UGy8dkRbET1GKUr2wFyI=", "dev": true, "requires": { - "ember-cli-babel": "6.10.0", + "ember-cli-babel": "6.11.0", "ember-getowner-polyfill": "2.2.0", "ember-macro-helpers": "0.17.0" } }, + "ember-rfc176-data": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.1.tgz", + "integrity": "sha512-u+W5rUvYO7xyKJjiPuCM7bIAvFyPwPTJ66fOZz1xuCv3AyReI9Oev5oOADOO6YJZk+vEn0xWiZ9N6zSf8WU7Fg==", + "dev": true + }, "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", diff --git a/package.json b/package.json index e77c3aa6..185ee987 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "ember-moment": "7.2.0", "ember-paper": "1.0.0-beta.4", "ember-phoenix": "^0.1.6", - "ember-power-calendar": "^0.6.2", + "ember-power-calendar": "^0.7.1", "ember-resolver": "^4.0.0", "ember-simple-auth": "1.2.0", "ember-source": "~2.17.0", From 4f718e84dc23b40d06605bdf5b41e634a06027b7 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 21 Dec 2017 16:50:17 -0600 Subject: [PATCH 10/46] Remove Ember Simple Auth for person tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems it can’t really handle using two different tokens for things, seems preferable to just bypass it for something this lightweight. --- app/adapters/commitment.js | 8 ++++- app/authenticators/commitment.js | 49 ------------------------------- app/authorizers/commitment.js | 13 -------- app/routes/calendar.js | 28 +++++++++++++----- app/services/account.js | 2 +- tests/acceptance/calendar-test.js | 5 ---- 6 files changed, 29 insertions(+), 76 deletions(-) delete mode 100644 app/authenticators/commitment.js delete mode 100644 app/authorizers/commitment.js diff --git a/app/adapters/commitment.js b/app/adapters/commitment.js index 2a163a05..5b05ba78 100644 --- a/app/adapters/commitment.js +++ b/app/adapters/commitment.js @@ -1,5 +1,11 @@ import ApplicationAdapter from './application'; +import { computed } from '@ember/object'; export default ApplicationAdapter.extend({ - authorizer: 'authorizer:commitment' + headers: computed(function() { + const personToken = localStorage.getItem('person-token'); + return { + 'Authorization': `Person Bearer ${personToken}` + }; + }).volatile() }); diff --git a/app/authenticators/commitment.js b/app/authenticators/commitment.js deleted file mode 100644 index 0e878795..00000000 --- a/app/authenticators/commitment.js +++ /dev/null @@ -1,49 +0,0 @@ -import Ember from 'ember'; - -import OAuth2PasswordGrant from 'ember-simple-auth/authenticators/oauth2-password-grant'; -import config from 'prison-rideshare-ui/config/environment'; - -import RSVP from 'rsvp'; -import { makeArray } from '@ember/array'; -import { isEmpty } from '@ember/utils'; -import { run } from '@ember/runloop'; -import { - merge, - assign as emberAssign -} from '@ember/polyfills'; - -const assign = emberAssign || merge; - -export default OAuth2PasswordGrant.extend({ - serverTokenEndpoint: `${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace}/people/token`, - - // FIXME this is overkill maybe??? - authenticate(magicToken, scope = [], headers = {}) { - return new RSVP.Promise((resolve, reject) => { - const data = { 'grant_type': 'magic', token: magicToken }; - const serverTokenEndpoint = this.get('serverTokenEndpoint'); - const useResponse = this.get('rejectWithResponse'); - const scopesString = makeArray(scope).join(' '); - if (!isEmpty(scopesString)) { - data.scope = scopesString; - } - this.makeRequest(serverTokenEndpoint, data, headers).then((response) => { - run(() => { - if (!this._validate(response)) { - reject('access_token is missing in server response'); - } - - const expiresAt = this._absolutizeExpirationTime(response['expires_in']); - this._scheduleAccessTokenRefresh(response['expires_in'], expiresAt, response['refresh_token']); - if (!isEmpty(expiresAt)) { - response = assign(response, { 'expires_at': expiresAt }); - } - - resolve(response); - }); - }, (response) => { - run(null, reject, useResponse ? response : (response.responseJSON || response.responseText)); - }); - }); - }, -}); diff --git a/app/authorizers/commitment.js b/app/authorizers/commitment.js deleted file mode 100644 index 18648255..00000000 --- a/app/authorizers/commitment.js +++ /dev/null @@ -1,13 +0,0 @@ -import OAuth2Bearer from 'ember-simple-auth/authorizers/oauth2-bearer'; -import { isEmpty } from '@ember/utils'; - -export default OAuth2Bearer.extend({ - authorize(data, block) { - // FIXME what if the access token is for the application authenticator??? - const accessToken = data['access_token']; - - if (!isEmpty(accessToken)) { - block('Authorization', `Person Bearer ${accessToken}`); - } - } -}); diff --git a/app/routes/calendar.js b/app/routes/calendar.js index ac02a3a2..b49dfb0a 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -1,15 +1,29 @@ import Route from '@ember/routing/route'; -import { inject as service } from '@ember/service'; +import RSVP from 'rsvp'; +import { isEmpty } from '@ember/utils'; +import Ember from 'ember'; +import fetch from 'fetch'; +import config from '../config/environment'; export default Route.extend({ - session: service(), - // FIXME is it possible to get the token from elsewhere than the transition object? model(params, { queryParams }) { - return this.get('session').authenticate( - 'authenticator:commitment', - queryParams.token - ).catch(error => { + return new RSVP.Promise((resolve, reject) => { + const token = queryParams.token; + const personTokenEndpoint = `${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace}/people/token`; + + if (!isEmpty(token)) { + fetch(personTokenEndpoint, { + method: 'POST', + body: `grant_type=magic&token=${token}` + }).then(raw => raw.json(), reject).then(data => { + localStorage.setItem('person-token', data.access_token); + resolve(); + }).catch(reject); + } else { + resolve(); + } + }).catch(error => { this.set('error', error); }).then(() => { return this.store.findAll('slot').catch(() => [ diff --git a/app/services/account.js b/app/services/account.js index fa9c23b9..48bc4e8d 100644 --- a/app/services/account.js +++ b/app/services/account.js @@ -18,7 +18,7 @@ export default Service.extend({ if (!isEmpty(token)) { fetch(`${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace.length > 0 ? `${config.DS.namespace}/` : ''}users/current`, { - type: 'GET', + method: 'GET', headers: { 'Authorization': `Bearer ${token}` } diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 6eeca611..e0cb6fd8 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -1,8 +1,6 @@ import { test } from 'qunit'; import moduleForAcceptance from 'prison-rideshare-ui/tests/helpers/module-for-acceptance'; -import { authenticateSession } from 'prison-rideshare-ui/tests/helpers/ember-simple-auth'; - import page from 'prison-rideshare-ui/tests/pages/calendar'; moduleForAcceptance('Acceptance | calendar', { @@ -28,9 +26,6 @@ moduleForAcceptance('Acceptance | calendar', { committedSlot.createCommitment({ }); - - // FIXME without this, the Person Bearer isn’t sent by the authoriser… ya - authenticateSession(this.application); } }); From 82c1d5fd50ec25ee52c5faf8c8cb3b5c28fbd8a3 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 21 Dec 2017 17:31:51 -0600 Subject: [PATCH 11/46] Add token encoding and proper header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There’s no test backing for the header 😐 --- app/routes/calendar.js | 5 ++++- mirage/config.js | 2 +- tests/acceptance/calendar-test.js | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/routes/calendar.js b/app/routes/calendar.js index b49dfb0a..9821f461 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -15,7 +15,10 @@ export default Route.extend({ if (!isEmpty(token)) { fetch(personTokenEndpoint, { method: 'POST', - body: `grant_type=magic&token=${token}` + body: `grant_type=magic&token=${encodeURIComponent(token)}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } }).then(raw => raw.json(), reject).then(data => { localStorage.setItem('person-token', data.access_token); resolve(); diff --git a/mirage/config.js b/mirage/config.js index a39a2d08..ffbba541 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -62,7 +62,7 @@ export default function() { this.post('/people/token', function(db, { requestBody }) { const bodyParams = parseQueryString(requestBody); - if (bodyParams.grant_type === 'magic' && bodyParams.token === 'MAGICTOKEN') { + if (bodyParams.grant_type === 'magic' && bodyParams.token === 'MAGIC??TOKEN') { return { access_token: 'XXX' }; diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index e0cb6fd8..3322f886 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -30,7 +30,7 @@ moduleForAcceptance('Acceptance | calendar', { }); test('calendar shows existing commitments and lets them be changed', function(assert) { - page.visit({ token: 'MAGICTOKEN' }); + page.visit({ token: 'MAGIC??TOKEN' }); andThen(function() { page.days(3).as(d4 => { From 2cb3cac45ff540046e90d294c387a01b90772a1b Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 21 Dec 2017 17:59:15 -0600 Subject: [PATCH 12/46] Add tokens to Mirage person model --- mirage/config.js | 7 ++++--- tests/acceptance/calendar-test.js | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mirage/config.js b/mirage/config.js index ffbba541..05333e11 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -59,12 +59,13 @@ export default function() { this.delete('/commitments/:id'); - this.post('/people/token', function(db, { requestBody }) { + this.post('/people/token', function({ people }, { requestBody }) { const bodyParams = parseQueryString(requestBody); + const person = people.findBy({magicToken: bodyParams.token}); - if (bodyParams.grant_type === 'magic' && bodyParams.token === 'MAGIC??TOKEN') { + if (bodyParams.grant_type === 'magic' && person) { return { - access_token: 'XXX' + access_token: person.accessToken }; } else { return new Mirage.Response(401, {}, {}); diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 3322f886..089dd464 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -26,6 +26,11 @@ moduleForAcceptance('Acceptance | calendar', { committedSlot.createCommitment({ }); + + server.create('person', { + magicToken: 'MAGIC??TOKEN', + accessToken: 'XXX' + }); } }); From 9db53ca74f09f22a62b956bd2823211eadcc656b Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 21 Dec 2017 22:53:35 -0600 Subject: [PATCH 13/46] =?UTF-8?q?Add=20display=20of=20person=20token?= =?UTF-8?q?=E2=80=99s=20email=20address?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/adapters/application.js | 9 +++++++++ app/controllers/calendar.js | 3 ++- app/routes/calendar.js | 13 ++++++++----- app/templates/calendar.hbs | 2 ++ mirage/config.js | 7 +++++++ tests/acceptance/calendar-test.js | 2 ++ tests/pages/calendar.js | 1 + 7 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app/adapters/application.js b/app/adapters/application.js index 97f9f13e..cd344676 100644 --- a/app/adapters/application.js +++ b/app/adapters/application.js @@ -15,5 +15,14 @@ export default DS.JSONAPIAdapter.extend(DataAdapterMixin, { default: return this._super(...arguments); } + }, + + urlForQueryRecord(query) { + if (query.me) { + delete query.me; + return `${this._super(...arguments)}/me`; + } + + return this._super(...arguments); } }); diff --git a/app/controllers/calendar.js b/app/controllers/calendar.js index bbbd7ef9..ada420a4 100644 --- a/app/controllers/calendar.js +++ b/app/controllers/calendar.js @@ -3,5 +3,6 @@ import Controller from '@ember/controller'; import { alias } from '@ember/object/computed'; export default Controller.extend({ - slots: alias('model') + slots: alias('model.slots'), + person: alias('model.person') }); diff --git a/app/routes/calendar.js b/app/routes/calendar.js index 9821f461..656f90ff 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -29,11 +29,14 @@ export default Route.extend({ }).catch(error => { this.set('error', error); }).then(() => { - return this.store.findAll('slot').catch(() => [ - this.store.createRecord('slot', {start: new Date(2017, 11, 3, 17), end: new Date(2017, 11, 3, 21), count: 2}), - this.store.createRecord('slot', {start: new Date(2017, 11, 3, 11), end: new Date(2017, 11, 3, 17), count: 3}), - this.store.createRecord('slot', {start: new Date(2017, 11, 8, 17), count: 4}) - ]); + return RSVP.hash({ + slots: this.store.findAll('slot').catch(() => [ + this.store.createRecord('slot', {start: new Date(2017, 11, 3, 17), end: new Date(2017, 11, 3, 21), count: 2}), + this.store.createRecord('slot', {start: new Date(2017, 11, 3, 11), end: new Date(2017, 11, 3, 17), count: 3}), + this.store.createRecord('slot', {start: new Date(2017, 11, 8, 17), count: 4}) + ]), + person: this.store.queryRecord('person', { me: true, token: localStorage.getItem('person-token') }) + }); }); } }); diff --git a/app/templates/calendar.hbs b/app/templates/calendar.hbs index 6d87b399..f2220835 100644 --- a/app/templates/calendar.hbs +++ b/app/templates/calendar.hbs @@ -1,3 +1,5 @@ +
You are logged in as {{person.email}}
+ {{#power-calendar daysComponent='calendar-days' as |calendar|}} {{calendar.nav}} diff --git a/mirage/config.js b/mirage/config.js index 05333e11..f2f425fe 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -71,6 +71,13 @@ export default function() { return new Mirage.Response(401, {}, {}); } }); + + this.get('/people/me', function({ people }, { queryParams }) { + const accessToken = queryParams.token; + const person = people.findBy({accessToken}); + + return person; + }); } // Taken from https://gist.github.com/Manc/9409355 diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 089dd464..0ac0e66c 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -28,6 +28,7 @@ moduleForAcceptance('Acceptance | calendar', { }); server.create('person', { + email: 'jorts@jants.ca', magicToken: 'MAGIC??TOKEN', accessToken: 'XXX' }); @@ -38,6 +39,7 @@ test('calendar shows existing commitments and lets them be changed', function(as page.visit({ token: 'MAGIC??TOKEN' }); andThen(function() { + assert.equal(page.personSession, 'You are logged in as jorts@jants.ca'); page.days(3).as(d4 => { assert.equal(d4.slots().count, 1, 'expected one slot on Monday'); d4.slots(0).as(s1 => { diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 9692ff35..066b8da6 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -9,6 +9,7 @@ import { export default create({ visit: visitable('/calendar'), + personSession: text('.person-session'), month: text('something'), days: collection({ From a1b5492674a0745753e8ad4089202ff2bf5ed421 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sat, 23 Dec 2017 22:14:51 -0600 Subject: [PATCH 14/46] Add handling for magic token exchange failure --- app/routes/calendar.js | 33 ++++++++++++++----------------- app/templates/calendar-error.hbs | 1 + mirage/config.js | 7 ++++++- tests/acceptance/calendar-test.js | 8 ++++++++ tests/pages/calendar.js | 4 +++- 5 files changed, 33 insertions(+), 20 deletions(-) create mode 100644 app/templates/calendar-error.hbs diff --git a/app/routes/calendar.js b/app/routes/calendar.js index 656f90ff..95d935c3 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -8,26 +8,23 @@ import config from '../config/environment'; export default Route.extend({ // FIXME is it possible to get the token from elsewhere than the transition object? model(params, { queryParams }) { - return new RSVP.Promise((resolve, reject) => { - const token = queryParams.token; - const personTokenEndpoint = `${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace}/people/token`; + const token = queryParams.token; + const personTokenEndpoint = `${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace}/people/token`; - if (!isEmpty(token)) { - fetch(personTokenEndpoint, { - method: 'POST', - body: `grant_type=magic&token=${encodeURIComponent(token)}`, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - } - }).then(raw => raw.json(), reject).then(data => { - localStorage.setItem('person-token', data.access_token); - resolve(); - }).catch(reject); - } else { - resolve(); + return fetch(personTokenEndpoint, { + method: 'POST', + body: `grant_type=magic&token=${encodeURIComponent(token)}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' } - }).catch(error => { - this.set('error', error); + }).then(response => { + if (response.ok) { + return response.json(); + } + + throw new Error('We were unable to log you in with that token.'); + }).then(data => { + localStorage.setItem('person-token', data.access_token); }).then(() => { return RSVP.hash({ slots: this.store.findAll('slot').catch(() => [ diff --git a/app/templates/calendar-error.hbs b/app/templates/calendar-error.hbs new file mode 100644 index 00000000..e52555f1 --- /dev/null +++ b/app/templates/calendar-error.hbs @@ -0,0 +1 @@ +
{{model.message}}
diff --git a/mirage/config.js b/mirage/config.js index f2f425fe..b21cc105 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -68,7 +68,12 @@ export default function() { access_token: person.accessToken }; } else { - return new Mirage.Response(401, {}, {}); + return new Mirage.Response(401, {}, { + errors: [{ + status: 401, + title: 'Unauthorized' + }] + }); } }); diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 0ac0e66c..6914a931 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -79,3 +79,11 @@ test('calendar shows existing commitments and lets them be changed', function(as assert.equal(commitment.slotId, this.toCommitSlot.id, 'expected the server to have the newly-created commitment'); }); }); + +test('visiting with an unknown magic token shows an error', function(assert) { + page.visit({ token: 'JORTLEBY' }); + + andThen(function() { + assert.equal(page.error, 'We were unable to log you in with that token.'); + }); +}); diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 066b8da6..6af5750c 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -27,5 +27,7 @@ export default create({ } }) } - }) + }), + + error: text('.error') }); From 6d2be0540269f0939d362776864ba2720af81ea1 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sat, 23 Dec 2017 22:19:00 -0600 Subject: [PATCH 15/46] Add handling for a missing magic token --- app/routes/calendar.js | 4 ++++ tests/acceptance/calendar-test.js | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/app/routes/calendar.js b/app/routes/calendar.js index 95d935c3..dd9b5b10 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -11,6 +11,10 @@ export default Route.extend({ const token = queryParams.token; const personTokenEndpoint = `${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace}/people/token`; + if (isEmpty(token)) { + throw new Error('We were unable to log you in without a token.'); + } + return fetch(personTokenEndpoint, { method: 'POST', body: `grant_type=magic&token=${encodeURIComponent(token)}`, diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 6914a931..3f701b25 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -87,3 +87,11 @@ test('visiting with an unknown magic token shows an error', function(assert) { assert.equal(page.error, 'We were unable to log you in with that token.'); }); }); + +test('visiting with no token shows an error', function(assert) { + page.visit(); + + andThen(function() { + assert.equal(page.error, 'We were unable to log you in without a token.'); + }); +}) From d8bfad626707d30169d71653c426c576b29a2efb Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sat, 23 Dec 2017 22:29:14 -0600 Subject: [PATCH 16/46] Add handling for person-fetch failure --- app/routes/calendar.js | 10 ++++++---- tests/acceptance/calendar-test.js | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/routes/calendar.js b/app/routes/calendar.js index dd9b5b10..89825127 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -27,16 +27,18 @@ export default Route.extend({ } throw new Error('We were unable to log you in with that token.'); - }).then(data => { - localStorage.setItem('person-token', data.access_token); - }).then(() => { + }).then(({ access_token }) => { + return this.store.queryRecord('person', { me: true, token: access_token }) + }).catch(() => { + throw new Error('We were unable to log you in with that token.'); + }).then(person => { return RSVP.hash({ slots: this.store.findAll('slot').catch(() => [ this.store.createRecord('slot', {start: new Date(2017, 11, 3, 17), end: new Date(2017, 11, 3, 21), count: 2}), this.store.createRecord('slot', {start: new Date(2017, 11, 3, 11), end: new Date(2017, 11, 3, 17), count: 3}), this.store.createRecord('slot', {start: new Date(2017, 11, 8, 17), count: 4}) ]), - person: this.store.queryRecord('person', { me: true, token: localStorage.getItem('person-token') }) + person }); }); } diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 3f701b25..24e3ff90 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -1,5 +1,6 @@ import { test } from 'qunit'; import moduleForAcceptance from 'prison-rideshare-ui/tests/helpers/module-for-acceptance'; +import Mirage from 'ember-cli-mirage'; import page from 'prison-rideshare-ui/tests/pages/calendar'; @@ -95,3 +96,20 @@ test('visiting with no token shows an error', function(assert) { assert.equal(page.error, 'We were unable to log you in without a token.'); }); }) + +test('visiting with a magic token that doesn’t resolve to a person shows an error', function(assert) { + server.get('/people/me', function() { + return new Mirage.Response(401, {}, { + errors: [{ + status: 401, + title: 'Unauthorized' + }] + }); + }); + + page.visit({ token: 'MAGIC??TOKEN' }); + + andThen(function() { + assert.equal(page.error, 'We were unable to log you in with that token.'); + }); +}); From 4b225a3ae4723218c16390b620fdd6b52be09723 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 00:52:59 -0600 Subject: [PATCH 17/46] Add handling for commitment-deletion failure --- app/components/calendar-slot.js | 9 ++++++++- tests/acceptance/calendar-test.js | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/components/calendar-slot.js b/app/components/calendar-slot.js index 7bd6e3a7..dd08bd82 100644 --- a/app/components/calendar-slot.js +++ b/app/components/calendar-slot.js @@ -1,8 +1,10 @@ import Component from '@ember/component'; import { computed } from '@ember/object'; import { inject as service } from '@ember/service'; +import config from 'prison-rideshare-ui/config/environment'; export default Component.extend({ + paperToaster: service(), store: service(), isCommittedTo: computed('slot.commitments.length', function() { @@ -15,7 +17,12 @@ export default Component.extend({ click() { if (this.get('isCommittedTo')) { - this.get('slot.commitments.firstObject').destroyRecord(); + this.get('slot.commitments.firstObject').destroyRecord().catch(() => { + this.get('paperToaster').show('Couldn’t save your change', { + duration: config.toastDuration, + position: 'top right' + }); + }); } else { this.get('store').createRecord('commitment', { slot: this.get('slot') }).save(); } diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 24e3ff90..a706e8a7 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -3,6 +3,7 @@ import moduleForAcceptance from 'prison-rideshare-ui/tests/helpers/module-for-ac import Mirage from 'ember-cli-mirage'; import page from 'prison-rideshare-ui/tests/pages/calendar'; +import shared from 'prison-rideshare-ui/tests/pages/shared'; moduleForAcceptance('Acceptance | calendar', { beforeEach() { @@ -81,6 +82,27 @@ test('calendar shows existing commitments and lets them be changed', function(as }); }); +test('a failure to delete a commitment keeps it displayed and shows an error', function(assert) { + server.delete('/commitments/:id', function() { + return new Mirage.Response(401, {}, { + errors: [{ + status: 401, + title: 'Unauthorized' + }] + }); + }); + + page.visit({ token: 'MAGIC??TOKEN' }); + + page.days(3).slots(0).click(); + + andThen(() => { + assert.equal(shared.toast.text, 'Couldn’t save your change'); + assert.ok(page.days(3).slots(0).isCommittedTo, 'expected the slot to still be committed-to'); + assert.equal(server.db.commitments.length, 1, 'expected the commitment to still be on the server'); + }); +}); + test('visiting with an unknown magic token shows an error', function(assert) { page.visit({ token: 'JORTLEBY' }); From 4f68620ca88b6e087873331b32f7b4181141d82a Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 09:19:07 -0600 Subject: [PATCH 18/46] Add preliminary calendar styling --- app/styles/calendar.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/styles/calendar.scss b/app/styles/calendar.scss index 60e440d2..faf7b1f2 100644 --- a/app/styles/calendar.scss +++ b/app/styles/calendar.scss @@ -3,3 +3,7 @@ background: blue; } } + +.ember-power-calendar { + @include ember-power-calendar(100px); +} From 4ba0bcc2f94182ef1a1fd8d034439d97de43f59c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 09:19:43 -0600 Subject: [PATCH 19/46] Add handling for commitment creation failure --- app/components/calendar-slot.js | 10 +++++++++- tests/acceptance/calendar-test.js | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/components/calendar-slot.js b/app/components/calendar-slot.js index dd08bd82..1578502a 100644 --- a/app/components/calendar-slot.js +++ b/app/components/calendar-slot.js @@ -24,7 +24,15 @@ export default Component.extend({ }); }); } else { - this.get('store').createRecord('commitment', { slot: this.get('slot') }).save(); + const newRecord = this.get('store').createRecord('commitment', { slot: this.get('slot') }); + + newRecord.save().catch(() => { + this.get('paperToaster').show('Couldn’t save your change', { + duration: config.toastDuration, + position: 'top right' + }); + newRecord.destroyRecord(); + }); } } }); diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index a706e8a7..d988a94e 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -103,6 +103,27 @@ test('a failure to delete a commitment keeps it displayed and shows an error', f }); }); +test('a failure to create a commitment makes it not display and shows an error', function(assert) { + server.post('/commitments', function() { + return new Mirage.Response(401, {}, { + errors: [{ + status: 401, + title: 'Unauthorized' + }] + }); + }); + + page.visit({ token: 'MAGIC??TOKEN' }); + + page.days(9).slots(1).click(); + + andThen(() => { + assert.equal(shared.toast.text, 'Couldn’t save your change'); + assert.notOk(page.days(9).slots(1).isCommittedTo, 'expected the slot to not be committed-to'); + assert.equal(server.db.commitments.length, 1, 'expected the commitments to be unchanged on the server'); + }); +}) + test('visiting with an unknown magic token shows an error', function(assert) { page.visit({ token: 'JORTLEBY' }); From a7359befd2bc2d300178fd1b8ffc012a7a796807 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 09:37:16 -0600 Subject: [PATCH 20/46] Restore storage of person token This is relied on by the adapter, the lack of erasure after tests led to false positives. Maybe there should be a service, or the token should be checked before trying to use the magic token, but LATER I guess --- app/routes/calendar.js | 1 + tests/helpers/destroy-app.js | 1 + 2 files changed, 2 insertions(+) diff --git a/app/routes/calendar.js b/app/routes/calendar.js index 89825127..9c13bff2 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -28,6 +28,7 @@ export default Route.extend({ throw new Error('We were unable to log you in with that token.'); }).then(({ access_token }) => { + localStorage.setItem('person-token', access_token); return this.store.queryRecord('person', { me: true, token: access_token }) }).catch(() => { throw new Error('We were unable to log you in with that token.'); diff --git a/tests/helpers/destroy-app.js b/tests/helpers/destroy-app.js index ac074c62..99029c00 100644 --- a/tests/helpers/destroy-app.js +++ b/tests/helpers/destroy-app.js @@ -3,4 +3,5 @@ import { run } from '@ember/runloop'; export default function destroyApp(application) { run(application, 'destroy'); server.shutdown(); + localStorage.removeItem('person-token'); } From 503e26fba0836789134af89b66a59f445cc39703 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 13:50:02 -0600 Subject: [PATCH 21/46] Remove count from calendar This really never should have been displayed. --- app/templates/components/calendar-slot.hbs | 2 +- tests/acceptance/calendar-test.js | 3 --- tests/pages/calendar.js | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/templates/components/calendar-slot.hbs b/app/templates/components/calendar-slot.hbs index 3963a88b..38effacb 100644 --- a/app/templates/components/calendar-slot.hbs +++ b/app/templates/components/calendar-slot.hbs @@ -1,3 +1,3 @@
- {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}}: {{slot.count}} + {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}}
diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index d988a94e..9e63f691 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -46,7 +46,6 @@ test('calendar shows existing commitments and lets them be changed', function(as assert.equal(d4.slots().count, 1, 'expected one slot on Monday'); d4.slots(0).as(s1 => { assert.equal(s1.hours, '5P–8P'); - assert.equal(s1.count, '2'); assert.ok(s1.isCommittedTo, 'expected the slot to be committed-to'); }) }); @@ -55,12 +54,10 @@ test('calendar shows existing commitments and lets them be changed', function(as assert.equal(d10.slots().count, 2, 'expected two slots on Sunday'); d10.slots(0).as(s1 => { assert.equal(s1.hours, '11A–5P'); - assert.equal(s1.count, '3'); assert.notOk(s1.isCommittedTo, 'expected the slot to not be committed-to'); }); d10.slots(1).as(s2 => { assert.equal(s2.hours, '5P–9P'); - assert.equal(s2.count, '2'); }); }); }); diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 6af5750c..d8510da8 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -21,7 +21,6 @@ export default create({ item: { hours: text('.hours'), - count: text('.count'), isCommittedTo: hasClass('is-committed-to') } From b3985b02dbbc9e5ab58d84d135c1584292ebf6e0 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 14:24:10 -0600 Subject: [PATCH 22/46] Add person to commitment creation --- app/components/calendar-slot.js | 5 ++++- app/models/commitment.js | 3 ++- app/templates/calendar.hbs | 2 +- app/templates/components/calendar-day.hbs | 2 +- mirage/config.js | 14 +++++++++----- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/app/components/calendar-slot.js b/app/components/calendar-slot.js index 1578502a..7cf37533 100644 --- a/app/components/calendar-slot.js +++ b/app/components/calendar-slot.js @@ -24,7 +24,10 @@ export default Component.extend({ }); }); } else { - const newRecord = this.get('store').createRecord('commitment', { slot: this.get('slot') }); + const newRecord = this.get('store').createRecord('commitment', { + slot: this.get('slot'), + person: this.get('person') + }); newRecord.save().catch(() => { this.get('paperToaster').show('Couldn’t save your change', { diff --git a/app/models/commitment.js b/app/models/commitment.js index 4d7678dc..202174e3 100644 --- a/app/models/commitment.js +++ b/app/models/commitment.js @@ -1,5 +1,6 @@ import DS from 'ember-data'; export default DS.Model.extend({ - slot: DS.belongsTo({ async: false }) + slot: DS.belongsTo({ async: false }), + person: DS.belongsTo({ async: false }) }); diff --git a/app/templates/calendar.hbs b/app/templates/calendar.hbs index f2220835..0cb809fa 100644 --- a/app/templates/calendar.hbs +++ b/app/templates/calendar.hbs @@ -4,6 +4,6 @@ {{calendar.nav}} {{#calendar.days showDaysAround=false as |day|}} - {{calendar-day day=day slots=slots}} + {{calendar-day day=day slots=slots person=person}} {{/calendar.days}} {{/power-calendar}} diff --git a/app/templates/components/calendar-day.hbs b/app/templates/components/calendar-day.hbs index bac521db..3b3e9acb 100644 --- a/app/templates/components/calendar-day.hbs +++ b/app/templates/components/calendar-day.hbs @@ -1,5 +1,5 @@ {{day.number}} {{#each daySlots as |slot|}} - {{calendar-slot slot=slot}} + {{calendar-slot slot=slot person=person}} {{/each}} diff --git a/mirage/config.js b/mirage/config.js index b21cc105..311666e1 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -48,13 +48,17 @@ export default function() { this.get('/slots'); - this.post('/commitments', function({ commitments }, request) { - if (request.requestHeaders.Authorization === 'Person Bearer XXX') { + this.post('/commitments', function({ commitments, people }, request) { + if (request.requestHeaders.Authorization.startsWith('Person Bearer')) { + const [, , accessToken] = request.requestHeaders.Authorization.split(' '); + const person = people.findBy({accessToken}); const attrs = this.normalizedRequestAttrs(); - return commitments.create(attrs); - } else { - return new Mirage.Response(401, {}, {}); + + if (person && attrs.personId === person.id) { + return commitments.create(attrs); + } } + return new Mirage.Response(401, {}, {}); }); this.delete('/commitments/:id'); From 5e5829febf8ae7c83c8cd52f823296eaaa3a6400 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 19:15:08 -0600 Subject: [PATCH 23/46] Add full slot detection/commitment-blocking --- app/components/calendar-slot.js | 12 +++---- app/models/slot.js | 10 +++++- app/styles/calendar.scss | 4 +++ app/templates/components/calendar-slot.hbs | 2 +- mirage/models/commitment.js | 1 + tests/acceptance/calendar-test.js | 39 ++++++++++++++++------ tests/pages/calendar.js | 3 +- 7 files changed, 51 insertions(+), 20 deletions(-) diff --git a/app/components/calendar-slot.js b/app/components/calendar-slot.js index 7cf37533..74f0171e 100644 --- a/app/components/calendar-slot.js +++ b/app/components/calendar-slot.js @@ -7,12 +7,10 @@ export default Component.extend({ paperToaster: service(), store: service(), - isCommittedTo: computed('slot.commitments.length', function() { - if (this.get('slot.commitments.length')) { - return true; - } else { - return false; - } + isCommittedTo: computed('slot.commitments.length', 'person', function() { + const personId = this.get('person.id'); + + return this.get('slot.commitments').map(slot => slot.belongsTo('person').id()).includes(personId); }), click() { @@ -23,7 +21,7 @@ export default Component.extend({ position: 'top right' }); }); - } else { + } else if (this.get('slot.isNotFull')) { const newRecord = this.get('store').createRecord('commitment', { slot: this.get('slot'), person: this.get('person') diff --git a/app/models/slot.js b/app/models/slot.js index 3d66319a..c269c649 100644 --- a/app/models/slot.js +++ b/app/models/slot.js @@ -1,9 +1,17 @@ import DS from 'ember-data'; +import { computed } from '@ember/object'; export default DS.Model.extend({ start: DS.attr('date'), end: DS.attr('date'), count: DS.attr('number'), - commitments: DS.hasMany({ async: false }) + commitments: DS.hasMany({ async: false }), + + isNotFull: computed('commitments.length', 'count', function() { + const count = this.get('count'); + const commitmentCount = this.get('commitments.length'); + + return count === 0 || commitmentCount < count; + }) }); diff --git a/app/styles/calendar.scss b/app/styles/calendar.scss index faf7b1f2..fd64bd4c 100644 --- a/app/styles/calendar.scss +++ b/app/styles/calendar.scss @@ -2,6 +2,10 @@ &.is-committed-to { background: blue; } + + &.is-full { + opacity: 0.5; + } } .ember-power-calendar { diff --git a/app/templates/components/calendar-slot.hbs b/app/templates/components/calendar-slot.hbs index 38effacb..f2bceda1 100644 --- a/app/templates/components/calendar-slot.hbs +++ b/app/templates/components/calendar-slot.hbs @@ -1,3 +1,3 @@ -
+
{{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}}
diff --git a/mirage/models/commitment.js b/mirage/models/commitment.js index 860b5ee9..ff1be7ca 100644 --- a/mirage/models/commitment.js +++ b/mirage/models/commitment.js @@ -1,5 +1,6 @@ import { Model, belongsTo } from 'ember-cli-mirage'; export default Model.extend({ + person: belongsTo(), slot: belongsTo() }); diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 9e63f691..f11821fb 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -7,6 +7,11 @@ import shared from 'prison-rideshare-ui/tests/pages/shared'; moduleForAcceptance('Acceptance | calendar', { beforeEach() { + const person = server.create('person', { + email: 'jorts@jants.ca', + magicToken: 'MAGIC??TOKEN', + accessToken: 'XXX' + }); const committedSlot = server.create('slot', { start: new Date(2017, 11, 4, 17), end: new Date(2017, 11, 4, 20), @@ -22,18 +27,10 @@ moduleForAcceptance('Acceptance | calendar', { server.create('slot', { start: new Date(2017, 11, 10, 11), end: new Date(2017, 11, 10, 17), - count: 3 - }); - - committedSlot.createCommitment({ - + count: 0 }); - server.create('person', { - email: 'jorts@jants.ca', - magicToken: 'MAGIC??TOKEN', - accessToken: 'XXX' - }); + committedSlot.createCommitment({ person }); } }); @@ -47,6 +44,7 @@ test('calendar shows existing commitments and lets them be changed', function(as d4.slots(0).as(s1 => { assert.equal(s1.hours, '5P–8P'); assert.ok(s1.isCommittedTo, 'expected the slot to be committed-to'); + assert.notOk(s1.isFull, 'expected the slot to not be full'); }) }); @@ -79,6 +77,27 @@ test('calendar shows existing commitments and lets them be changed', function(as }); }); +test('full slots show as full and can’t be committed to', function(assert) { + server.post('/commitments', function() { + assert.ok(false, 'expected no commitment to be created for a full slot'); + }); + + this.toCommitSlot.createCommitment(); + this.toCommitSlot.createCommitment(); + + page.visit({ token: 'MAGIC??TOKEN' }); + + andThen(() => { + assert.ok(page.days(9).slots(1).isFull, 'expected the full slot to show as full'); + }); + + page.days(9).slots(1).click(); + + andThen(() => { + assert.notOk(page.days(9).slots(1).isCommittedTo, 'expected the slot to not be committed-to'); + }); +}); + test('a failure to delete a commitment keeps it displayed and shows an error', function(assert) { server.delete('/commitments/:id', function() { return new Mirage.Response(401, {}, { diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index d8510da8..2d56cd61 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -22,7 +22,8 @@ export default create({ item: { hours: text('.hours'), - isCommittedTo: hasClass('is-committed-to') + isCommittedTo: hasClass('is-committed-to'), + isFull: hasClass('is-full') } }) } From 6544700873fa958f6b396cd4db6ebdd14a23a601 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 19:35:50 -0600 Subject: [PATCH 24/46] Remove unused property --- app/components/calendar-day.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/components/calendar-day.js b/app/components/calendar-day.js index 1f659b52..9287c7fa 100644 --- a/app/components/calendar-day.js +++ b/app/components/calendar-day.js @@ -7,12 +7,5 @@ export default Component.extend({ const slots = this.get('slots'); return slots.filter(slot => dayDateString === slot.get('start').toDateString()).sortBy('start'); - }), - - slot: computed('day.id', 'slots.@each.start', function() { - const dayDateString = this.get('day.date').toDateString(); - const slots = this.get('slots'); - - return slots.find(slot => dayDateString === slot.get('start').toDateString()); }) }); From b3a43ef3391d360a57a6ebb72d0302778bf1dd83 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 19:37:12 -0600 Subject: [PATCH 25/46] Add missing whitespace --- tests/acceptance/calendar-test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index f11821fb..6321bbc8 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -12,6 +12,7 @@ moduleForAcceptance('Acceptance | calendar', { magicToken: 'MAGIC??TOKEN', accessToken: 'XXX' }); + const committedSlot = server.create('slot', { start: new Date(2017, 11, 4, 17), end: new Date(2017, 11, 4, 20), From daaccf0ff77214103a0d0523215aca794292bda1 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 24 Dec 2017 21:02:55 -0600 Subject: [PATCH 26/46] Change commitment-deletion to be properly scoped --- app/components/calendar-slot.js | 9 ++++++--- tests/acceptance/calendar-test.js | 11 ++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/components/calendar-slot.js b/app/components/calendar-slot.js index 74f0171e..5daa683b 100644 --- a/app/components/calendar-slot.js +++ b/app/components/calendar-slot.js @@ -1,5 +1,6 @@ import Component from '@ember/component'; import { computed } from '@ember/object'; +import { reads } from '@ember/object/computed'; import { inject as service } from '@ember/service'; import config from 'prison-rideshare-ui/config/environment'; @@ -7,15 +8,17 @@ export default Component.extend({ paperToaster: service(), store: service(), - isCommittedTo: computed('slot.commitments.length', 'person', function() { + isCommittedTo: reads('commitment'), + + commitment: computed('slot.commitments.@each.person', 'person', function() { const personId = this.get('person.id'); - return this.get('slot.commitments').map(slot => slot.belongsTo('person').id()).includes(personId); + return this.get('slot.commitments').find(slot => slot.belongsTo('person').id() == personId); }), click() { if (this.get('isCommittedTo')) { - this.get('slot.commitments.firstObject').destroyRecord().catch(() => { + this.get('commitment').destroyRecord().catch(() => { this.get('paperToaster').show('Couldn’t save your change', { duration: config.toastDuration, position: 'top right' diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 6321bbc8..d116ca9c 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -16,7 +16,7 @@ moduleForAcceptance('Acceptance | calendar', { const committedSlot = server.create('slot', { start: new Date(2017, 11, 4, 17), end: new Date(2017, 11, 4, 20), - count: 2 + count: 3 }); this.toCommitSlot = server.create('slot', { @@ -31,6 +31,7 @@ moduleForAcceptance('Acceptance | calendar', { count: 0 }); + committedSlot.createCommitment(); committedSlot.createCommitment({ person }); } }); @@ -65,7 +66,7 @@ test('calendar shows existing commitments and lets them be changed', function(as andThen(() => { assert.notOk(page.days(3).slots(0).isCommittedTo, 'expected the slot to not longer be committed-to'); - assert.equal(server.db.commitments.length, 0, 'expected the commitment to have been deleted on the server'); + assert.equal(server.db.commitments.length, 1, 'expected the commitment to have been deleted on the server'); }); page.days(9).slots(1).click(); @@ -73,7 +74,7 @@ test('calendar shows existing commitments and lets them be changed', function(as andThen(() => { assert.ok(page.days(9).slots(1).isCommittedTo, 'expected the slot to be newly committed-to'); - const [commitment] = server.db.commitments; + const [, commitment] = server.db.commitments; assert.equal(commitment.slotId, this.toCommitSlot.id, 'expected the server to have the newly-created commitment'); }); }); @@ -116,7 +117,7 @@ test('a failure to delete a commitment keeps it displayed and shows an error', f andThen(() => { assert.equal(shared.toast.text, 'Couldn’t save your change'); assert.ok(page.days(3).slots(0).isCommittedTo, 'expected the slot to still be committed-to'); - assert.equal(server.db.commitments.length, 1, 'expected the commitment to still be on the server'); + assert.equal(server.db.commitments.length, 2, 'expected the commitment to still be on the server'); }); }); @@ -137,7 +138,7 @@ test('a failure to create a commitment makes it not display and shows an error', andThen(() => { assert.equal(shared.toast.text, 'Couldn’t save your change'); assert.notOk(page.days(9).slots(1).isCommittedTo, 'expected the slot to not be committed-to'); - assert.equal(server.db.commitments.length, 1, 'expected the commitments to be unchanged on the server'); + assert.equal(server.db.commitments.length, 2, 'expected the commitments to be unchanged on the server'); }); }) From 0ff8a4017a87db65afc7db7555c861f998d3d118 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 29 Dec 2017 16:00:31 -0600 Subject: [PATCH 27/46] Add assertion on calendar month --- tests/acceptance/calendar-test.js | 2 ++ tests/pages/calendar.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index d116ca9c..78b01788 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -41,6 +41,8 @@ test('calendar shows existing commitments and lets them be changed', function(as andThen(function() { assert.equal(page.personSession, 'You are logged in as jorts@jants.ca'); + assert.equal(page.month, 'December 2017'); + page.days(3).as(d4 => { assert.equal(d4.slots().count, 1, 'expected one slot on Monday'); d4.slots(0).as(s1 => { diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 2d56cd61..7836d779 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -10,7 +10,7 @@ export default create({ visit: visitable('/calendar'), personSession: text('.person-session'), - month: text('something'), + month: text('.ember-power-calendar-nav-title'), days: collection({ itemScope: '.ember-power-calendar-day', From 0722ce5a9a6397b195cff1d301e937def3be6727 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 29 Dec 2017 16:26:00 -0600 Subject: [PATCH 28/46] Add month to calendar path --- app/controllers/calendar.js | 1 + app/router.js | 2 +- app/routes/calendar.js | 5 +++-- app/templates/calendar.hbs | 2 +- tests/acceptance/calendar-test.js | 22 +++++++++++++++------- tests/pages/calendar.js | 2 +- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/app/controllers/calendar.js b/app/controllers/calendar.js index ada420a4..5c4fc8fc 100644 --- a/app/controllers/calendar.js +++ b/app/controllers/calendar.js @@ -3,6 +3,7 @@ import Controller from '@ember/controller'; import { alias } from '@ember/object/computed'; export default Controller.extend({ + month: alias('model.month'), slots: alias('model.slots'), person: alias('model.person') }); diff --git a/app/router.js b/app/router.js index 5c492fdf..ff5484f0 100644 --- a/app/router.js +++ b/app/router.js @@ -28,7 +28,7 @@ Router.map(function() { this.route('login'); this.route('register'); - this.route('calendar'); + this.route('calendar', { path: '/calendar/:month' }); }); export default Router; diff --git a/app/routes/calendar.js b/app/routes/calendar.js index 9c13bff2..664f7777 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -7,7 +7,7 @@ import config from '../config/environment'; export default Route.extend({ // FIXME is it possible to get the token from elsewhere than the transition object? - model(params, { queryParams }) { + model({ month }, { queryParams }) { const token = queryParams.token; const personTokenEndpoint = `${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace}/people/token`; @@ -39,7 +39,8 @@ export default Route.extend({ this.store.createRecord('slot', {start: new Date(2017, 11, 3, 11), end: new Date(2017, 11, 3, 17), count: 3}), this.store.createRecord('slot', {start: new Date(2017, 11, 8, 17), count: 4}) ]), - person + person, + month }); }); } diff --git a/app/templates/calendar.hbs b/app/templates/calendar.hbs index 0cb809fa..4a81256c 100644 --- a/app/templates/calendar.hbs +++ b/app/templates/calendar.hbs @@ -1,6 +1,6 @@
You are logged in as {{person.email}}
-{{#power-calendar daysComponent='calendar-days' as |calendar|}} +{{#power-calendar center=month daysComponent='calendar-days' as |calendar|}} {{calendar.nav}} {{#calendar.days showDaysAround=false as |day|}} diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 78b01788..a9a48107 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -37,7 +37,7 @@ moduleForAcceptance('Acceptance | calendar', { }); test('calendar shows existing commitments and lets them be changed', function(assert) { - page.visit({ token: 'MAGIC??TOKEN' }); + page.visit({ month: '2017-12', token: 'MAGIC??TOKEN' }); andThen(function() { assert.equal(page.personSession, 'You are logged in as jorts@jants.ca'); @@ -89,7 +89,7 @@ test('full slots show as full and can’t be committed to', function(assert) { this.toCommitSlot.createCommitment(); this.toCommitSlot.createCommitment(); - page.visit({ token: 'MAGIC??TOKEN' }); + page.visit({ month: '2017-12', token: 'MAGIC??TOKEN' }); andThen(() => { assert.ok(page.days(9).slots(1).isFull, 'expected the full slot to show as full'); @@ -112,7 +112,7 @@ test('a failure to delete a commitment keeps it displayed and shows an error', f }); }); - page.visit({ token: 'MAGIC??TOKEN' }); + page.visit({ month: '2017-12', token: 'MAGIC??TOKEN' }); page.days(3).slots(0).click(); @@ -133,7 +133,7 @@ test('a failure to create a commitment makes it not display and shows an error', }); }); - page.visit({ token: 'MAGIC??TOKEN' }); + page.visit({ month: '2017-12', token: 'MAGIC??TOKEN' }); page.days(9).slots(1).click(); @@ -145,7 +145,7 @@ test('a failure to create a commitment makes it not display and shows an error', }) test('visiting with an unknown magic token shows an error', function(assert) { - page.visit({ token: 'JORTLEBY' }); + page.visit({ month: '2017-12', token: 'JORTLEBY' }); andThen(function() { assert.equal(page.error, 'We were unable to log you in with that token.'); @@ -153,7 +153,7 @@ test('visiting with an unknown magic token shows an error', function(assert) { }); test('visiting with no token shows an error', function(assert) { - page.visit(); + page.visit({ month: '2017-12' }); andThen(function() { assert.equal(page.error, 'We were unable to log you in without a token.'); @@ -170,9 +170,17 @@ test('visiting with a magic token that doesn’t resolve to a person shows an er }); }); - page.visit({ token: 'MAGIC??TOKEN' }); + page.visit({ month: '2017-12', token: 'MAGIC??TOKEN' }); andThen(function() { assert.equal(page.error, 'We were unable to log you in with that token.'); }); }); + +test('the path controls the month', function(assert) { + page.visit({ month: '2018-01', token: 'MAGIC??TOKEN' }); + + andThen(function() { + assert.equal(page.month, 'January 2018'); + }); +}); diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 7836d779..26b4cb03 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -7,7 +7,7 @@ import { } from 'ember-cli-page-object'; export default create({ - visit: visitable('/calendar'), + visit: visitable('/calendar/:month'), personSession: text('.person-session'), month: text('.ember-power-calendar-nav-title'), From 5f4bd7bc04eb4e428ca50d190fadfba83ab7b367 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 29 Dec 2017 20:37:54 -0600 Subject: [PATCH 29/46] Add checkbox for slot commitment indicator --- app/components/calendar-slot.js | 38 ++++++++++++---------- app/styles/calendar.scss | 10 ------ app/templates/components/calendar-slot.hbs | 6 ++-- tests/pages/calendar.js | 11 +++++-- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/app/components/calendar-slot.js b/app/components/calendar-slot.js index 5daa683b..0f885805 100644 --- a/app/components/calendar-slot.js +++ b/app/components/calendar-slot.js @@ -16,27 +16,29 @@ export default Component.extend({ return this.get('slot.commitments').find(slot => slot.belongsTo('person').id() == personId); }), - click() { - if (this.get('isCommittedTo')) { - this.get('commitment').destroyRecord().catch(() => { - this.get('paperToaster').show('Couldn’t save your change', { - duration: config.toastDuration, - position: 'top right' + actions: { + toggle() { + if (this.get('isCommittedTo')) { + this.get('commitment').destroyRecord().catch(() => { + this.get('paperToaster').show('Couldn’t save your change', { + duration: config.toastDuration, + position: 'top right' + }); + }); + } else if (this.get('slot.isNotFull')) { + const newRecord = this.get('store').createRecord('commitment', { + slot: this.get('slot'), + person: this.get('person') }); - }); - } else if (this.get('slot.isNotFull')) { - const newRecord = this.get('store').createRecord('commitment', { - slot: this.get('slot'), - person: this.get('person') - }); - newRecord.save().catch(() => { - this.get('paperToaster').show('Couldn’t save your change', { - duration: config.toastDuration, - position: 'top right' + newRecord.save().catch(() => { + this.get('paperToaster').show('Couldn’t save your change', { + duration: config.toastDuration, + position: 'top right' + }); + newRecord.destroyRecord(); }); - newRecord.destroyRecord(); - }); + } } } }); diff --git a/app/styles/calendar.scss b/app/styles/calendar.scss index fd64bd4c..1ed7ec65 100644 --- a/app/styles/calendar.scss +++ b/app/styles/calendar.scss @@ -1,13 +1,3 @@ -.slot { - &.is-committed-to { - background: blue; - } - - &.is-full { - opacity: 0.5; - } -} - .ember-power-calendar { @include ember-power-calendar(100px); } diff --git a/app/templates/components/calendar-slot.hbs b/app/templates/components/calendar-slot.hbs index f2bceda1..d0970d36 100644 --- a/app/templates/components/calendar-slot.hbs +++ b/app/templates/components/calendar-slot.hbs @@ -1,3 +1,5 @@ -
- {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}} +
+ {{#paper-checkbox value=isCommittedTo disabled=(not slot.isNotFull) onChange=(action 'toggle')}} + {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}} + {{/paper-checkbox}}
diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 26b4cb03..9c8443d3 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -1,10 +1,12 @@ import { + attribute, collection, create, hasClass, text, visitable } from 'ember-cli-page-object'; +import { getter } from 'ember-cli-page-object/macros'; export default create({ visit: visitable('/calendar/:month'), @@ -17,13 +19,16 @@ export default create({ item: { slots: collection({ - itemScope: '.slot', + itemScope: '.slot md-checkbox', item: { hours: text('.hours'), - isCommittedTo: hasClass('is-committed-to'), - isFull: hasClass('is-full') + isCommittedTo: hasClass('md-checked'), + disabledAttribute: attribute('disabled'), + isFull: getter(function() { + return this.disabledAttribute === 'disabled'; + }) } }) } From d671fb78bf6f7b77c4464bbf06e97b7d51a12e9b Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 2 Jan 2018 14:34:43 -0600 Subject: [PATCH 30/46] Add ember-cli-poll --- package-lock.json | 220 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 221 insertions(+) diff --git a/package-lock.json b/package-lock.json index 55550b36..8ec2ebc4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6966,6 +6966,226 @@ "integrity": "sha1-Tjmvi1UwHN3FAXc5t3qAT7ogce0=", "dev": true }, + "ember-cli-poll": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ember-cli-poll/-/ember-cli-poll-0.1.0.tgz", + "integrity": "sha1-Ve6NnYywiw4fCVRLaeiYxJdH6L4=", + "dev": true, + "requires": { + "ember-cli-babel": "5.2.4" + }, + "dependencies": { + "babel-core": { + "version": "5.8.38", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz", + "integrity": "sha1-H8ruedfmG3ULALjlT238nQr4ZVg=", + "dev": true, + "requires": { + "babel-plugin-constant-folding": "1.0.1", + "babel-plugin-dead-code-elimination": "1.0.2", + "babel-plugin-eval": "1.0.1", + "babel-plugin-inline-environment-variables": "1.0.1", + "babel-plugin-jscript": "1.0.4", + "babel-plugin-member-expression-literals": "1.0.1", + "babel-plugin-property-literals": "1.0.1", + "babel-plugin-proto-to-assign": "1.0.4", + "babel-plugin-react-constant-elements": "1.0.3", + "babel-plugin-react-display-name": "1.0.3", + "babel-plugin-remove-console": "1.0.1", + "babel-plugin-remove-debugger": "1.0.1", + "babel-plugin-runtime": "1.0.7", + "babel-plugin-undeclared-variables-check": "1.0.2", + "babel-plugin-undefined-to-void": "1.1.6", + "babylon": "5.8.38", + "bluebird": "2.11.0", + "chalk": "1.1.3", + "convert-source-map": "1.5.0", + "core-js": "1.2.7", + "debug": "2.6.8", + "detect-indent": "3.0.1", + "esutils": "2.0.2", + "fs-readdir-recursive": "0.1.2", + "globals": "6.4.1", + "home-or-tmp": "1.0.0", + "is-integer": "1.0.7", + "js-tokens": "1.0.1", + "json5": "0.4.0", + "lodash": "3.10.1", + "minimatch": "2.0.10", + "output-file-sync": "1.1.2", + "path-exists": "1.0.0", + "path-is-absolute": "1.0.1", + "private": "0.1.7", + "regenerator": "0.8.40", + "regexpu": "1.3.0", + "repeating": "1.1.3", + "resolve": "1.4.0", + "shebang-regex": "1.0.0", + "slash": "1.0.0", + "source-map": "0.5.7", + "source-map-support": "0.2.10", + "to-fast-properties": "1.0.3", + "trim-right": "1.0.1", + "try-resolve": "1.0.1" + } + }, + "babylon": { + "version": "5.8.38", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz", + "integrity": "sha1-7JsSCxG/bM1Bc6GL8hfmC3mFn/0=", + "dev": true + }, + "broccoli-babel-transpiler": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.2.tgz", + "integrity": "sha512-vFQ+aSR9J81fm3MXXQGgDxswYINHl2p5duLvRLVnpmgPDNdpdsa30gh3xnmhzR/GwWFBfUNle7aYxthlgvsN0w==", + "dev": true, + "requires": { + "babel-core": "5.8.38", + "broccoli-funnel": "1.2.0", + "broccoli-merge-trees": "1.2.4", + "broccoli-persistent-filter": "1.4.3", + "clone": "0.2.0", + "hash-for-dep": "1.2.0", + "heimdalljs-logger": "0.1.9", + "json-stable-stringify": "1.0.1", + "rsvp": "3.6.2", + "workerpool": "2.2.4" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", + "dev": true + } + } + }, + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "dev": true + }, + "detect-indent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", + "integrity": "sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U=", + "dev": true, + "requires": { + "get-stdin": "4.0.1", + "minimist": "1.2.0", + "repeating": "1.1.3" + } + }, + "ember-cli-babel": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz", + "integrity": "sha1-XOT0awjtb20h6Hhhn7aJcZ1ujhM=", + "dev": true, + "requires": { + "broccoli-babel-transpiler": "5.7.2", + "broccoli-funnel": "1.2.0", + "clone": "2.1.1", + "ember-cli-version-checker": "1.3.1", + "resolve": "1.4.0" + } + }, + "ember-cli-version-checker": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz", + "integrity": "sha1-C8LRNMgwFC2mS/lieg7e0QthrnI=", + "dev": true, + "requires": { + "semver": "5.4.1" + } + }, + "globals": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz", + "integrity": "sha1-hJgDKzttHMge68X3lpDY/in6v08=", + "dev": true + }, + "home-or-tmp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz", + "integrity": "sha1-S58eQIAMPlDGwn94FnavzOcfOYU=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2", + "user-home": "1.1.1" + } + }, + "js-tokens": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz", + "integrity": "sha1-zENaXIuUrRWst5gxQPyAGCyJrq4=", + "dev": true + }, + "json5": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz", + "integrity": "sha1-BUNS5MTIDIbAkjh31EneF2pzLI0=", + "dev": true + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "path-exists": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz", + "integrity": "sha1-1aiZjrce83p0w06w2eum6HjuoIE=", + "dev": true + }, + "repeating": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", + "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "source-map-support": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz", + "integrity": "sha1-6lo5AKHByyUJagrozFwrSxDe09w=", + "dev": true, + "requires": { + "source-map": "0.1.32" + }, + "dependencies": { + "source-map": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", + "integrity": "sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + } + } + }, "ember-cli-preprocess-registry": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz", diff --git a/package.json b/package.json index 185ee987..bfbf45c7 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "ember-cli-mirage": "^0.3.4", "ember-cli-moment-shim": "3.0.1", "ember-cli-page-object": "1.11.0", + "ember-cli-poll": "^0.1.0", "ember-cli-qunit": "^4.1.1", "ember-cli-sass": "^7.1.1", "ember-cli-sentry": "^3.0.0-beta", From 3de52db0b4fb161ec863faa94094c4ebd7ee8947 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 2 Jan 2018 15:42:03 -0600 Subject: [PATCH 31/46] Add ESLint workaround --- mirage/serializers/slot.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mirage/serializers/slot.js b/mirage/serializers/slot.js index a2edf62a..d640b783 100644 --- a/mirage/serializers/slot.js +++ b/mirage/serializers/slot.js @@ -1,5 +1,6 @@ import { JSONAPISerializer } from 'ember-cli-mirage'; export default JSONAPISerializer.extend({ + // eslint-disable-next-line ember/avoid-leaking-state-in-ember-objects include: ['commitments'] }); From 6b7b990cde1ad3b71c30f20b4335982389855e89 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 2 Jan 2018 16:12:45 -0600 Subject: [PATCH 32/46] Update dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There’s a deprecation warning about project.nodeModulesPath that’s fixed with some of these, though ember-cli-document-title hasn’t yet been updated so the warning remains. --- package-lock.json | 522 +++++----------------------------------------- package.json | 6 +- 2 files changed, 55 insertions(+), 473 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3c1f9c6d..9450e042 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1630,60 +1630,43 @@ } }, "body-parser": { - "version": "1.17.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz", - "integrity": "sha1-+IkqvI+eYn1Crtr7yma/WrmRBO4=", + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", "dev": true, "requires": { - "bytes": "2.4.0", - "content-type": "1.0.2", - "debug": "2.6.7", + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", "depd": "1.1.1", "http-errors": "1.6.2", - "iconv-lite": "0.4.15", + "iconv-lite": "0.4.19", "on-finished": "2.3.0", - "qs": "6.4.0", - "raw-body": "2.2.0", + "qs": "6.5.1", + "raw-body": "2.3.2", "type-is": "1.6.15" }, "dependencies": { - "bytes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", - "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=", - "dev": true - }, "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "iconv-lite": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", - "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", "dev": true }, "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", "dev": true - }, - "raw-body": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", - "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=", - "dev": true, - "requires": { - "bytes": "2.4.0", - "iconv-lite": "0.4.15", - "unpipe": "1.0.0" - } } } }, @@ -3440,9 +3423,9 @@ "dev": true }, "content-type": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", - "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "continuable-cache": { @@ -4142,223 +4125,12 @@ } }, "ember-buffered-proxy": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/ember-buffered-proxy/-/ember-buffered-proxy-0.6.0.tgz", - "integrity": "sha1-RXW/ihbkrChxHj9Xd4mET2WhRAk=", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/ember-buffered-proxy/-/ember-buffered-proxy-0.8.1.tgz", + "integrity": "sha1-2Jwiydt29BG/ksezcEroxwiHy/o=", "dev": true, "requires": { - "ember-cli-babel": "5.2.4" - }, - "dependencies": { - "babel-core": { - "version": "5.8.38", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz", - "integrity": "sha1-H8ruedfmG3ULALjlT238nQr4ZVg=", - "dev": true, - "requires": { - "babel-plugin-constant-folding": "1.0.1", - "babel-plugin-dead-code-elimination": "1.0.2", - "babel-plugin-eval": "1.0.1", - "babel-plugin-inline-environment-variables": "1.0.1", - "babel-plugin-jscript": "1.0.4", - "babel-plugin-member-expression-literals": "1.0.1", - "babel-plugin-property-literals": "1.0.1", - "babel-plugin-proto-to-assign": "1.0.4", - "babel-plugin-react-constant-elements": "1.0.3", - "babel-plugin-react-display-name": "1.0.3", - "babel-plugin-remove-console": "1.0.1", - "babel-plugin-remove-debugger": "1.0.1", - "babel-plugin-runtime": "1.0.7", - "babel-plugin-undeclared-variables-check": "1.0.2", - "babel-plugin-undefined-to-void": "1.1.6", - "babylon": "5.8.38", - "bluebird": "2.11.0", - "chalk": "1.1.3", - "convert-source-map": "1.5.0", - "core-js": "1.2.7", - "debug": "2.6.8", - "detect-indent": "3.0.1", - "esutils": "2.0.2", - "fs-readdir-recursive": "0.1.2", - "globals": "6.4.1", - "home-or-tmp": "1.0.0", - "is-integer": "1.0.7", - "js-tokens": "1.0.1", - "json5": "0.4.0", - "lodash": "3.10.1", - "minimatch": "2.0.10", - "output-file-sync": "1.1.2", - "path-exists": "1.0.0", - "path-is-absolute": "1.0.1", - "private": "0.1.7", - "regenerator": "0.8.40", - "regexpu": "1.3.0", - "repeating": "1.1.3", - "resolve": "1.4.0", - "shebang-regex": "1.0.0", - "slash": "1.0.0", - "source-map": "0.5.7", - "source-map-support": "0.2.10", - "to-fast-properties": "1.0.3", - "trim-right": "1.0.1", - "try-resolve": "1.0.1" - } - }, - "babylon": { - "version": "5.8.38", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz", - "integrity": "sha1-7JsSCxG/bM1Bc6GL8hfmC3mFn/0=", - "dev": true - }, - "broccoli-babel-transpiler": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.2.tgz", - "integrity": "sha512-vFQ+aSR9J81fm3MXXQGgDxswYINHl2p5duLvRLVnpmgPDNdpdsa30gh3xnmhzR/GwWFBfUNle7aYxthlgvsN0w==", - "dev": true, - "requires": { - "babel-core": "5.8.38", - "broccoli-funnel": "1.2.0", - "broccoli-merge-trees": "1.2.4", - "broccoli-persistent-filter": "1.4.3", - "clone": "0.2.0", - "hash-for-dep": "1.2.0", - "heimdalljs-logger": "0.1.9", - "json-stable-stringify": "1.0.1", - "rsvp": "3.6.2", - "workerpool": "2.2.4" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - } - } - }, - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", - "dev": true - }, - "detect-indent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", - "integrity": "sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U=", - "dev": true, - "requires": { - "get-stdin": "4.0.1", - "minimist": "1.2.0", - "repeating": "1.1.3" - } - }, - "ember-cli-babel": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz", - "integrity": "sha1-XOT0awjtb20h6Hhhn7aJcZ1ujhM=", - "dev": true, - "requires": { - "broccoli-babel-transpiler": "5.7.2", - "broccoli-funnel": "1.2.0", - "clone": "2.1.1", - "ember-cli-version-checker": "1.3.1", - "resolve": "1.4.0" - } - }, - "ember-cli-version-checker": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz", - "integrity": "sha1-C8LRNMgwFC2mS/lieg7e0QthrnI=", - "dev": true, - "requires": { - "semver": "5.4.1" - } - }, - "globals": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz", - "integrity": "sha1-hJgDKzttHMge68X3lpDY/in6v08=", - "dev": true - }, - "home-or-tmp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz", - "integrity": "sha1-S58eQIAMPlDGwn94FnavzOcfOYU=", - "dev": true, - "requires": { - "os-tmpdir": "1.0.2", - "user-home": "1.1.1" - } - }, - "js-tokens": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz", - "integrity": "sha1-zENaXIuUrRWst5gxQPyAGCyJrq4=", - "dev": true - }, - "json5": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz", - "integrity": "sha1-BUNS5MTIDIbAkjh31EneF2pzLI0=", - "dev": true - }, - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", - "dev": true - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "path-exists": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz", - "integrity": "sha1-1aiZjrce83p0w06w2eum6HjuoIE=", - "dev": true - }, - "repeating": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", - "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", - "dev": true, - "requires": { - "is-finite": "1.0.2" - } - }, - "source-map-support": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz", - "integrity": "sha1-6lo5AKHByyUJagrozFwrSxDe09w=", - "dev": true, - "requires": { - "source-map": "0.1.32" - }, - "dependencies": { - "source-map": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", - "integrity": "sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=", - "dev": true, - "requires": { - "amdefine": "1.0.1" - } - } - } - } + "ember-cli-babel": "6.8.2" } }, "ember-cli": { @@ -4653,19 +4425,20 @@ } }, "ember-cli-code-coverage": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/ember-cli-code-coverage/-/ember-cli-code-coverage-0.3.12.tgz", - "integrity": "sha1-YTmtZD6ILI3XOPa8C0gPz9Oks1E=", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/ember-cli-code-coverage/-/ember-cli-code-coverage-0.4.2.tgz", + "integrity": "sha1-vSI69FPvC4DlSCzJlYzZcmtYZcc=", "dev": true, "requires": { - "babel-core": "5.8.38", - "body-parser": "1.17.2", + "babel-core": "6.26.0", + "babel-plugin-transform-async-to-generator": "6.24.1", + "body-parser": "1.18.2", "broccoli-filter": "1.2.4", "broccoli-funnel": "1.2.0", "broccoli-merge-trees": "1.2.4", - "ember-cli-babel": "5.2.4", + "ember-cli-babel": "6.8.2", "escodegen": "1.8.1", - "esprima": "2.7.3", + "esprima": "3.1.3", "exists-sync": "0.0.3", "extend": "3.0.1", "fs-extra": "0.26.7", @@ -4676,131 +4449,12 @@ "string.prototype.startswith": "0.2.0" }, "dependencies": { - "babel-core": { - "version": "5.8.38", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz", - "integrity": "sha1-H8ruedfmG3ULALjlT238nQr4ZVg=", - "dev": true, - "requires": { - "babel-plugin-constant-folding": "1.0.1", - "babel-plugin-dead-code-elimination": "1.0.2", - "babel-plugin-eval": "1.0.1", - "babel-plugin-inline-environment-variables": "1.0.1", - "babel-plugin-jscript": "1.0.4", - "babel-plugin-member-expression-literals": "1.0.1", - "babel-plugin-property-literals": "1.0.1", - "babel-plugin-proto-to-assign": "1.0.4", - "babel-plugin-react-constant-elements": "1.0.3", - "babel-plugin-react-display-name": "1.0.3", - "babel-plugin-remove-console": "1.0.1", - "babel-plugin-remove-debugger": "1.0.1", - "babel-plugin-runtime": "1.0.7", - "babel-plugin-undeclared-variables-check": "1.0.2", - "babel-plugin-undefined-to-void": "1.1.6", - "babylon": "5.8.38", - "bluebird": "2.11.0", - "chalk": "1.1.3", - "convert-source-map": "1.5.0", - "core-js": "1.2.7", - "debug": "2.6.8", - "detect-indent": "3.0.1", - "esutils": "2.0.2", - "fs-readdir-recursive": "0.1.2", - "globals": "6.4.1", - "home-or-tmp": "1.0.0", - "is-integer": "1.0.7", - "js-tokens": "1.0.1", - "json5": "0.4.0", - "lodash": "3.10.1", - "minimatch": "2.0.10", - "output-file-sync": "1.1.2", - "path-exists": "1.0.0", - "path-is-absolute": "1.0.1", - "private": "0.1.7", - "regenerator": "0.8.40", - "regexpu": "1.3.0", - "repeating": "1.1.3", - "resolve": "1.4.0", - "shebang-regex": "1.0.0", - "slash": "1.0.0", - "source-map": "0.5.6", - "source-map-support": "0.2.10", - "to-fast-properties": "1.0.3", - "trim-right": "1.0.1", - "try-resolve": "1.0.1" - } - }, - "babylon": { - "version": "5.8.38", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz", - "integrity": "sha1-7JsSCxG/bM1Bc6GL8hfmC3mFn/0=", - "dev": true - }, - "broccoli-babel-transpiler": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.2.tgz", - "integrity": "sha512-vFQ+aSR9J81fm3MXXQGgDxswYINHl2p5duLvRLVnpmgPDNdpdsa30gh3xnmhzR/GwWFBfUNle7aYxthlgvsN0w==", - "dev": true, - "requires": { - "babel-core": "5.8.38", - "broccoli-funnel": "1.2.0", - "broccoli-merge-trees": "1.2.4", - "broccoli-persistent-filter": "1.4.3", - "clone": "0.2.0", - "hash-for-dep": "1.2.0", - "heimdalljs-logger": "0.1.9", - "json-stable-stringify": "1.0.1", - "rsvp": "3.6.2", - "workerpool": "2.2.4" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - } - } - }, - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", "dev": true }, - "detect-indent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", - "integrity": "sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U=", - "dev": true, - "requires": { - "get-stdin": "4.0.1", - "minimist": "1.2.0", - "repeating": "1.1.3" - } - }, - "ember-cli-babel": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz", - "integrity": "sha1-XOT0awjtb20h6Hhhn7aJcZ1ujhM=", - "dev": true, - "requires": { - "broccoli-babel-transpiler": "5.7.2", - "broccoli-funnel": "1.2.0", - "clone": "2.1.1", - "ember-cli-version-checker": "1.3.1", - "resolve": "1.4.0" - } - }, - "ember-cli-version-checker": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz", - "integrity": "sha1-C8LRNMgwFC2mS/lieg7e0QthrnI=", - "dev": true, - "requires": { - "semver": "5.4.1" - } - }, "exists-sync": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz", @@ -4820,107 +4474,35 @@ "rimraf": "2.6.1" } }, - "globals": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz", - "integrity": "sha1-hJgDKzttHMge68X3lpDY/in6v08=", - "dev": true - }, - "home-or-tmp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz", - "integrity": "sha1-S58eQIAMPlDGwn94FnavzOcfOYU=", - "dev": true, - "requires": { - "os-tmpdir": "1.0.2", - "user-home": "1.1.1" - } - }, - "js-tokens": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz", - "integrity": "sha1-zENaXIuUrRWst5gxQPyAGCyJrq4=", - "dev": true - }, - "json5": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz", - "integrity": "sha1-BUNS5MTIDIbAkjh31EneF2pzLI0=", - "dev": true - }, - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", - "dev": true - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "path-exists": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz", - "integrity": "sha1-1aiZjrce83p0w06w2eum6HjuoIE=", - "dev": true - }, - "repeating": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", - "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", - "dev": true, - "requires": { - "is-finite": "1.0.2" - } - }, "source-map": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", "dev": true - }, - "source-map-support": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz", - "integrity": "sha1-6lo5AKHByyUJagrozFwrSxDe09w=", - "dev": true, - "requires": { - "source-map": "0.1.32" - }, - "dependencies": { - "source-map": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", - "integrity": "sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=", - "dev": true, - "requires": { - "amdefine": "1.0.1" - } - } - } } } }, "ember-cli-dependency-checker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-2.0.1.tgz", - "integrity": "sha512-eL7P3nCmekZ7pR1M+lTjZm2FnxTRQ14eVDbcGIFeku5v5GrCSSLYUB4wqSBlkhCmakOdmgXzAnHIpQGmk4WBuw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-2.1.0.tgz", + "integrity": "sha1-nWYoanx3jpRzPq8hMg0SnE/Q3WQ=", "dev": true, "requires": { "chalk": "1.1.3", "is-git-url": "1.0.0", + "resolve": "1.5.0", "semver": "5.4.1" + }, + "dependencies": { + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + } } }, "ember-cli-deploy": { diff --git a/package.json b/package.json index a645d447..3cde3837 100644 --- a/package.json +++ b/package.json @@ -22,13 +22,13 @@ "coveralls": "^2.12.0", "ember-ajax": "^3.0.0", "ember-browserify": "^1.1.14", - "ember-buffered-proxy": "0.6.0", + "ember-buffered-proxy": "^0.8.1", "ember-cli": "~2.18.0", "ember-cli-app-version": "^3.0.0", "ember-cli-babel": "^6.7.1", "ember-cli-clipboard": "^0.8.1", - "ember-cli-code-coverage": "^0.3.11", - "ember-cli-dependency-checker": "^2.0.0", + "ember-cli-code-coverage": "^0.4.1", + "ember-cli-dependency-checker": "^2.1.0", "ember-cli-deploy": "^1.0.2", "ember-cli-deploy-lightning-pack": "^1.1.2", "ember-cli-deploy-ssh-tunnel": "^1.0.0", From 4921fed8fc367734013238fc494f800619b8cdfe Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 2 Jan 2018 16:46:54 -0600 Subject: [PATCH 33/46] Add simple polling for slots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is tragique but I can’t handle looking at channels at the moment. --- app/routes/application.js | 9 +++++++++ app/routes/calendar.js | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/app/routes/application.js b/app/routes/application.js index 3ddd536d..e33e53f9 100644 --- a/app/routes/application.js +++ b/app/routes/application.js @@ -8,11 +8,20 @@ export default Route.extend(ApplicationRouteMixin, { account: service(), userSocket: service(), flashMessages: service(), + poll: service(), beforeModel() { return this._loadCurrentUser(); }, + afterModel() { + this._super(...arguments); + this.get('poll').start({ + idle_timeout: 10000, + interval: 10000 + }); + }, + title(tokens) { return `${tokens.join(' · ')} · Prison Rideshare`; }, diff --git a/app/routes/calendar.js b/app/routes/calendar.js index 664f7777..a2208b22 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -1,11 +1,14 @@ import Route from '@ember/routing/route'; import RSVP from 'rsvp'; +import { inject as service } from '@ember/service'; import { isEmpty } from '@ember/utils'; import Ember from 'ember'; import fetch from 'fetch'; import config from '../config/environment'; export default Route.extend({ + poll: service(), + // FIXME is it possible to get the token from elsewhere than the transition object? model({ month }, { queryParams }) { const token = queryParams.token; @@ -43,5 +46,22 @@ export default Route.extend({ month }); }); + }, + + afterModel() { + const url = this.store.adapterFor('application').buildURL('slot'); + + this.get('poll').setup({ + name: 'slotsPoll', + resource_name: 'slots', + url + }); + }, + + actions: { + willTransition(transition) { + this._super(transition); + this.get('poll').removePoll('slotsPoll'); + } } }); From 2a549ce0b4855bdc8a0e90c1d203e6b11aa807c3 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 2 Jan 2018 22:43:08 -0600 Subject: [PATCH 34/46] Add progress toward admin calendar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This would be better under the same route but it’s okay here for now. --- app/components/person-badge.js | 13 ++++++++++ app/controllers/admin-calendar.js | 9 +++++++ app/models/commitment.js | 2 +- app/router.js | 1 + app/routes/admin-calendar.js | 11 ++++++++ app/styles/app.scss | 2 +- app/templates/admin-calendar.hbs | 15 +++++++++++ app/templates/components/calendar-day.hbs | 2 +- app/templates/components/calendar-slot.hbs | 3 +++ app/templates/components/person-badge.hbs | 29 ++++++++++++++++++++++ app/templates/components/ride-person.hbs | 28 +-------------------- mirage/config.js | 1 + tests/acceptance/calendar-test.js | 29 +++++++++++++++++++++- tests/pages/calendar.js | 24 +++++++++++++++--- 14 files changed, 135 insertions(+), 34 deletions(-) create mode 100644 app/components/person-badge.js create mode 100644 app/controllers/admin-calendar.js create mode 100644 app/routes/admin-calendar.js create mode 100644 app/templates/admin-calendar.hbs create mode 100644 app/templates/components/person-badge.hbs diff --git a/app/components/person-badge.js b/app/components/person-badge.js new file mode 100644 index 00000000..346cee6c --- /dev/null +++ b/app/components/person-badge.js @@ -0,0 +1,13 @@ +import Component from '@ember/component'; + +export default Component.extend({ + classNames: ['person-badge'], + + showContact: false, + + actions: { + toggleContact() { + this.toggleProperty('showContact'); + } + } +}); diff --git a/app/controllers/admin-calendar.js b/app/controllers/admin-calendar.js new file mode 100644 index 00000000..286d3c05 --- /dev/null +++ b/app/controllers/admin-calendar.js @@ -0,0 +1,9 @@ +import CalendarController from './calendar'; + +export default CalendarController.extend({ + actions: { + setViewingSlot(slot) { + this.set('viewingSlot', slot); + } + } +}); diff --git a/app/models/commitment.js b/app/models/commitment.js index 202174e3..7de20627 100644 --- a/app/models/commitment.js +++ b/app/models/commitment.js @@ -2,5 +2,5 @@ import DS from 'ember-data'; export default DS.Model.extend({ slot: DS.belongsTo({ async: false }), - person: DS.belongsTo({ async: false }) + person: DS.belongsTo() }); diff --git a/app/router.js b/app/router.js index ff5484f0..bc637f99 100644 --- a/app/router.js +++ b/app/router.js @@ -28,6 +28,7 @@ Router.map(function() { this.route('login'); this.route('register'); + this.route('admin-calendar', { path: '/admin-calendar/:month' }); this.route('calendar', { path: '/calendar/:month' }); }); diff --git a/app/routes/admin-calendar.js b/app/routes/admin-calendar.js new file mode 100644 index 00000000..df18823a --- /dev/null +++ b/app/routes/admin-calendar.js @@ -0,0 +1,11 @@ +import Route from '@ember/routing/route'; +import RSVP from 'rsvp'; + +export default Route.extend({ + model({ month }) { + return RSVP.hash({ + slots: this.store.findAll('slot'), + month + }); + } +}); diff --git a/app/styles/app.scss b/app/styles/app.scss index b0246c96..ca5acf48 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -223,7 +223,7 @@ md-table-container.debts .person .name { } } -.ride-person { +.person-badge { display: inline-block; background-color: #e0e0e0; color: #424242; diff --git a/app/templates/admin-calendar.hbs b/app/templates/admin-calendar.hbs new file mode 100644 index 00000000..b1ca9718 --- /dev/null +++ b/app/templates/admin-calendar.hbs @@ -0,0 +1,15 @@ +{{#power-calendar center=month daysComponent='calendar-days' as |calendar|}} + {{calendar.nav}} + + {{#calendar.days showDaysAround=false as |day|}} + {{calendar-day day=day slots=slots count=true setViewingSlot=(action 'setViewingSlot')}} + {{/calendar.days}} +{{/power-calendar}} + +{{#if viewingSlot.commitments}} +
    + {{#each viewingSlot.commitments as |commitment|}} +
  • {{person-badge person=commitment.person}}
  • + {{/each}} +
+{{/if}} diff --git a/app/templates/components/calendar-day.hbs b/app/templates/components/calendar-day.hbs index 3b3e9acb..db1571e1 100644 --- a/app/templates/components/calendar-day.hbs +++ b/app/templates/components/calendar-day.hbs @@ -1,5 +1,5 @@ {{day.number}} {{#each daySlots as |slot|}} - {{calendar-slot slot=slot person=person}} + {{calendar-slot slot=slot person=person count=count setViewingSlot=setViewingSlot}} {{/each}} diff --git a/app/templates/components/calendar-slot.hbs b/app/templates/components/calendar-slot.hbs index d0970d36..6cf04c69 100644 --- a/app/templates/components/calendar-slot.hbs +++ b/app/templates/components/calendar-slot.hbs @@ -2,4 +2,7 @@ {{#paper-checkbox value=isCommittedTo disabled=(not slot.isNotFull) onChange=(action 'toggle')}} {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}} {{/paper-checkbox}} + {{#if count}} + {{slot.commitments.length}} + {{/if}}
diff --git a/app/templates/components/person-badge.hbs b/app/templates/components/person-badge.hbs new file mode 100644 index 00000000..b10d7ce4 --- /dev/null +++ b/app/templates/components/person-badge.hbs @@ -0,0 +1,29 @@ +
+ {{#if (eq property 'driver')}} + {{paper-icon 'person' size=14 title='driver'}} + {{else if (eq property 'carOwner')}} + {{paper-icon 'local gas station' size=14 title='car owner'}} + {{/if}} + {{person.name}} + {{#if clear}} + + + + {{/if}} +
+{{#if showContact}} + +{{/if}} diff --git a/app/templates/components/ride-person.hbs b/app/templates/components/ride-person.hbs index e4ff228c..146094b6 100644 --- a/app/templates/components/ride-person.hbs +++ b/app/templates/components/ride-person.hbs @@ -1,32 +1,6 @@ {{#if person}} -
- {{#if (eq property 'driver')}} - {{paper-icon 'person' size=14 title='driver'}} - {{else}} - {{paper-icon 'local gas station' size=14 title='car owner'}} - {{/if}} - {{person.name}} - - - -
- {{#if showContact}} - - {{/if}} + {{person-badge person=person property=property clear=(action 'clear')}}
{{else}} {{#paper-select diff --git a/mirage/config.js b/mirage/config.js index 311666e1..1b621401 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -29,6 +29,7 @@ export default function() { this.patch('/institutions/:id'); this.get('/people'); + this.get('/people/:id'); this.post('/people'); this.patch('/people/:id'); diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index a9a48107..e4049e44 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -1,6 +1,7 @@ import { test } from 'qunit'; import moduleForAcceptance from 'prison-rideshare-ui/tests/helpers/module-for-acceptance'; import Mirage from 'ember-cli-mirage'; +import { authenticateSession } from 'prison-rideshare-ui/tests/helpers/ember-simple-auth'; import page from 'prison-rideshare-ui/tests/pages/calendar'; import shared from 'prison-rideshare-ui/tests/pages/shared'; @@ -31,7 +32,7 @@ moduleForAcceptance('Acceptance | calendar', { count: 0 }); - committedSlot.createCommitment(); + committedSlot.createCommitment({ person: server.create('person', { name: 'Other Slot Person '})}); committedSlot.createCommitment({ person }); } }); @@ -49,6 +50,7 @@ test('calendar shows existing commitments and lets them be changed', function(as assert.equal(s1.hours, '5P–8P'); assert.ok(s1.isCommittedTo, 'expected the slot to be committed-to'); assert.notOk(s1.isFull, 'expected the slot to not be full'); + assert.notOk(s1.count.isVisible, 'expected the slot count not to show for a non-admin'); }) }); @@ -184,3 +186,28 @@ test('the path controls the month', function(assert) { assert.equal(page.month, 'January 2018'); }); }); + +test('an admin can see the commitments with person names', function(assert) { + server.create('user', { admin: true }); + authenticateSession(this.application, { access_token: 'abcdef' }); + page.adminVisit({ month: '2017-12' }); + + andThen(() => { + assert.equal(page.days(3).slots(0).count.text, 2, 'expected two people to show for the slot'); + assert.equal(page.people().count, 0, 'expected no people details to show initially'); + }); + + page.days(3).slots(0).count.click(); + + andThen(() => { + assert.equal(page.people().count, 2, 'expected two people details to show for the slot'); + assert.equal(page.people(0).name, 'Other Slot Person'); + assert.equal(page.people(1).name, 'Jortle Tortle'); + }); + + page.people(1).reveal(); + + andThen(() => { + assert.equal(page.people(1).email, 'jorts@jants.ca', 'expected the contact information to be revealed'); + }); +}); diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 9c8443d3..20bcdc65 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -1,5 +1,6 @@ import { attribute, + clickable, collection, create, hasClass, @@ -10,6 +11,7 @@ import { getter } from 'ember-cli-page-object/macros'; export default create({ visit: visitable('/calendar/:month'), + adminVisit: visitable('/admin-calendar/:month'), personSession: text('.person-session'), month: text('.ember-power-calendar-nav-title'), @@ -19,13 +21,18 @@ export default create({ item: { slots: collection({ - itemScope: '.slot md-checkbox', + itemScope: '.slot', item: { + click: clickable('md-checkbox'), hours: text('.hours'), - isCommittedTo: hasClass('md-checked'), - disabledAttribute: attribute('disabled'), + count: { + scope: '.count' + }, + + isCommittedTo: hasClass('md-checked', 'md-checkbox'), + disabledAttribute: attribute('disabled', 'md-checkbox'), isFull: getter(function() { return this.disabledAttribute === 'disabled'; }) @@ -34,5 +41,16 @@ export default create({ } }), + people: collection({ + itemScope: '.person-badge', + + item: { + text: text('.name'), + reveal: clickable('.name-container'), + + email: text('.email') + } + }), + error: text('.error') }); From 06eb2bac0104b6a13ac9c016be73d38f002030c4 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 2 Jan 2018 22:44:50 -0600 Subject: [PATCH 35/46] Add guard against polling in testing --- app/routes/application.js | 11 +++++++---- app/routes/calendar.js | 12 +++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/routes/application.js b/app/routes/application.js index e33e53f9..5d529e3d 100644 --- a/app/routes/application.js +++ b/app/routes/application.js @@ -1,5 +1,6 @@ import { inject as service } from '@ember/service'; import Route from '@ember/routing/route'; +import Ember from 'ember'; import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin'; @@ -16,10 +17,12 @@ export default Route.extend(ApplicationRouteMixin, { afterModel() { this._super(...arguments); - this.get('poll').start({ - idle_timeout: 10000, - interval: 10000 - }); + if (!Ember.testing) { + this.get('poll').start({ + idle_timeout: 10000, + interval: 10000 + }); + } }, title(tokens) { diff --git a/app/routes/calendar.js b/app/routes/calendar.js index a2208b22..8c90e55f 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -51,11 +51,13 @@ export default Route.extend({ afterModel() { const url = this.store.adapterFor('application').buildURL('slot'); - this.get('poll').setup({ - name: 'slotsPoll', - resource_name: 'slots', - url - }); + if (!Ember.testing) { + this.get('poll').setup({ + name: 'slotsPoll', + resource_name: 'slots', + url + }); + } }, actions: { From 8905cb2f44653b72c76f3823ddf4876a06e8ae39 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 2 Jan 2018 22:59:53 -0600 Subject: [PATCH 36/46] Correct admin calendar test --- tests/acceptance/calendar-test.js | 1 + tests/pages/calendar.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index e4049e44..3fc773ce 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -9,6 +9,7 @@ import shared from 'prison-rideshare-ui/tests/pages/shared'; moduleForAcceptance('Acceptance | calendar', { beforeEach() { const person = server.create('person', { + name: 'Jortle Tortle', email: 'jorts@jants.ca', magicToken: 'MAGIC??TOKEN', accessToken: 'XXX' diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 20bcdc65..1774b3ec 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -45,7 +45,7 @@ export default create({ itemScope: '.person-badge', item: { - text: text('.name'), + name: text('.name'), reveal: clickable('.name-container'), email: text('.email') From f3293b9de6dfb8a1ed3b68f12f58ec8ae407726b Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 2 Jan 2018 23:10:24 -0600 Subject: [PATCH 37/46] Add admin ability to move between months --- app/templates/admin-calendar.hbs | 10 ++++++++-- tests/acceptance/calendar-test.js | 12 ++++++++++++ tests/pages/calendar.js | 8 ++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/app/templates/admin-calendar.hbs b/app/templates/admin-calendar.hbs index b1ca9718..7e399cc3 100644 --- a/app/templates/admin-calendar.hbs +++ b/app/templates/admin-calendar.hbs @@ -1,5 +1,11 @@ -{{#power-calendar center=month daysComponent='calendar-days' as |calendar|}} - {{calendar.nav}} +{{#power-calendar center=month daysComponent='calendar-days' onCenterChange=(action (mut month) value="date") as |calendar|}} + {{#calendar.days showDaysAround=false as |day|}} {{calendar-day day=day slots=slots count=true setViewingSlot=(action 'setViewingSlot')}} diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 3fc773ce..3530f0ab 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -211,4 +211,16 @@ test('an admin can see the commitments with person names', function(assert) { andThen(() => { assert.equal(page.people(1).email, 'jorts@jants.ca', 'expected the contact information to be revealed'); }); + + page.nextMonth.click(); + + andThen(() => { + assert.equal(page.month, 'January 2018'); + }); + + page.previousMonth.click(); + + andThen(() => { + assert.equal(page.month, 'December 2017'); + }); }); diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 1774b3ec..caf97417 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -16,6 +16,14 @@ export default create({ personSession: text('.person-session'), month: text('.ember-power-calendar-nav-title'), + nextMonth: { + scope: '.ember-power-calendar-nav-control.next-month' + }, + + previousMonth: { + scope: '.ember-power-calendar-nav-control.previous-month' + }, + days: collection({ itemScope: '.ember-power-calendar-day', From 91e06f2cd1757c06d734713d4a6ac23dbfeb5981 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 2 Jan 2018 23:23:07 -0600 Subject: [PATCH 38/46] Hide checkbox on admin calendar --- app/templates/components/calendar-slot.hbs | 8 +++++--- tests/acceptance/calendar-test.js | 1 + tests/pages/calendar.js | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/templates/components/calendar-slot.hbs b/app/templates/components/calendar-slot.hbs index 6cf04c69..b081192c 100644 --- a/app/templates/components/calendar-slot.hbs +++ b/app/templates/components/calendar-slot.hbs @@ -1,8 +1,10 @@
- {{#paper-checkbox value=isCommittedTo disabled=(not slot.isNotFull) onChange=(action 'toggle')}} - {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}} - {{/paper-checkbox}} {{#if count}} + {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}} {{slot.commitments.length}} + {{else}} + {{#paper-checkbox value=isCommittedTo disabled=(not slot.isNotFull) onChange=(action 'toggle')}} + {{moment-format slot.start 'hA'}}–{{moment-format slot.end 'hA'}} + {{/paper-checkbox}} {{/if}}
diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 3530f0ab..9d1cb489 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -195,6 +195,7 @@ test('an admin can see the commitments with person names', function(assert) { andThen(() => { assert.equal(page.days(3).slots(0).count.text, 2, 'expected two people to show for the slot'); + assert.ok(page.days(3).slots(0).checkbox.isHidden, 'expected the checkbox to not display'); assert.equal(page.people().count, 0, 'expected no people details to show initially'); }); diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index caf97417..498a77c5 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -33,6 +33,7 @@ export default create({ item: { click: clickable('md-checkbox'), + checkbox: { scope: 'md-checkbox' }, hours: text('.hours'), count: { From 1bbe3cf7a7ca65d3982bd7560ef208d6ae1274c1 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 3 Jan 2018 09:32:50 -0600 Subject: [PATCH 39/46] Update appearance of slot count --- app/styles/calendar.scss | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/styles/calendar.scss b/app/styles/calendar.scss index 1ed7ec65..3913c2d8 100644 --- a/app/styles/calendar.scss +++ b/app/styles/calendar.scss @@ -1,3 +1,18 @@ .ember-power-calendar { @include ember-power-calendar(100px); + + .count { + display: inline-block; + width: 1rem; + height: 1rem; + + font-size: 75%; + text-align: center; + + border-radius: 5rem; + background-color: $dark-contrast-color; + color: white; + + cursor: pointer; + } } From 29d48317e5b0fda532f93006045d3f6b15203fe8 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 3 Jan 2018 09:52:00 -0600 Subject: [PATCH 40/46] Add title for currently-viewed slot --- app/templates/admin-calendar.hbs | 5 +++-- tests/acceptance/calendar-test.js | 1 + tests/pages/calendar.js | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/templates/admin-calendar.hbs b/app/templates/admin-calendar.hbs index 7e399cc3..d8e0a8ca 100644 --- a/app/templates/admin-calendar.hbs +++ b/app/templates/admin-calendar.hbs @@ -13,9 +13,10 @@ {{/power-calendar}} {{#if viewingSlot.commitments}} -
    +
    +

    {{moment-format viewingSlot.start 'dddd, MMMM D, hA'}}–{{moment-format viewingSlot.end 'hA'}}

    {{#each viewingSlot.commitments as |commitment|}}
  • {{person-badge person=commitment.person}}
  • {{/each}} -
+
{{/if}} diff --git a/tests/acceptance/calendar-test.js b/tests/acceptance/calendar-test.js index 9d1cb489..5c869560 100644 --- a/tests/acceptance/calendar-test.js +++ b/tests/acceptance/calendar-test.js @@ -202,6 +202,7 @@ test('an admin can see the commitments with person names', function(assert) { page.days(3).slots(0).count.click(); andThen(() => { + assert.equal(page.viewingSlot, 'Monday, December 4, 5P–8P'); assert.equal(page.people().count, 2, 'expected two people details to show for the slot'); assert.equal(page.people(0).name, 'Other Slot Person'); assert.equal(page.people(1).name, 'Jortle Tortle'); diff --git a/tests/pages/calendar.js b/tests/pages/calendar.js index 498a77c5..0c7349e9 100644 --- a/tests/pages/calendar.js +++ b/tests/pages/calendar.js @@ -50,6 +50,8 @@ export default create({ } }), + viewingSlot: text('.viewing-slot .hours'), + people: collection({ itemScope: '.person-badge', From 48f113ac9e3d41982074068561fc7c27b19eb1b2 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 3 Jan 2018 10:28:24 -0600 Subject: [PATCH 41/46] Move viewed slot to second column --- app/styles/calendar.scss | 4 ++++ app/templates/admin-calendar.hbs | 40 +++++++++++++++++--------------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/app/styles/calendar.scss b/app/styles/calendar.scss index 3913c2d8..ba3306b9 100644 --- a/app/styles/calendar.scss +++ b/app/styles/calendar.scss @@ -16,3 +16,7 @@ cursor: pointer; } } + +.admin-calendar { + display: flex; +} diff --git a/app/templates/admin-calendar.hbs b/app/templates/admin-calendar.hbs index d8e0a8ca..e1e6cc3d 100644 --- a/app/templates/admin-calendar.hbs +++ b/app/templates/admin-calendar.hbs @@ -1,22 +1,24 @@ -{{#power-calendar center=month daysComponent='calendar-days' onCenterChange=(action (mut month) value="date") as |calendar|}} - +
+ {{#power-calendar center=month daysComponent='calendar-days' onCenterChange=(action (mut month) value="date") as |calendar|}} + - {{#calendar.days showDaysAround=false as |day|}} - {{calendar-day day=day slots=slots count=true setViewingSlot=(action 'setViewingSlot')}} - {{/calendar.days}} -{{/power-calendar}} + {{#calendar.days showDaysAround=false as |day|}} + {{calendar-day day=day slots=slots count=true setViewingSlot=(action 'setViewingSlot')}} + {{/calendar.days}} + {{/power-calendar}} -{{#if viewingSlot.commitments}} -
-

{{moment-format viewingSlot.start 'dddd, MMMM D, hA'}}–{{moment-format viewingSlot.end 'hA'}}

- {{#each viewingSlot.commitments as |commitment|}} -
  • {{person-badge person=commitment.person}}
  • - {{/each}} + {{#if viewingSlot.commitments}} +
    +

    {{moment-format viewingSlot.start 'dddd, MMMM D, hA'}}–{{moment-format viewingSlot.end 'hA'}}

    + {{#each viewingSlot.commitments as |commitment|}} + {{person-badge person=commitment.person}} + {{/each}} +
    + {{/if}}
    -{{/if}} From b4c489140b9f82b8524d68ac93e104eb871fa82e Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 3 Jan 2018 10:36:42 -0600 Subject: [PATCH 42/46] Add link to admin calendar --- app/templates/application.hbs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/templates/application.hbs b/app/templates/application.hbs index cb2c1805..3a31a006 100644 --- a/app/templates/application.hbs +++ b/app/templates/application.hbs @@ -29,6 +29,9 @@ {{#paper-item}} {{#link-to 'institutions'}}Institutions{{/link-to}} {{/paper-item}} + {{#paper-item}} + {{#link-to 'admin-calendar' (moment-format (now) 'YYYY-MM')}}Calendar{{/link-to}} + {{/paper-item}} {{/if}} {{#paper-item}} {{#link-to 'reports.new'}}Report{{/link-to}} From 2b0e30371504a303c5c2199314b462144d86c74d Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 5 Jan 2018 04:55:16 -0600 Subject: [PATCH 43/46] Remove unused method This is in person-badge now. --- app/components/ride-person.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/components/ride-person.js b/app/components/ride-person.js index 2ff3676d..3a9e2584 100644 --- a/app/components/ride-person.js +++ b/app/components/ride-person.js @@ -27,10 +27,6 @@ export default Component.extend({ const ride = this.get('ride'); ride.set(this.get('property'), null); return ride.save(); - }, - - toggleContact() { - this.toggleProperty('showContact'); } } }); From 725d27b58b773a9b81857b035365f9eea4a2757a Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 5 Jan 2018 05:07:56 -0600 Subject: [PATCH 44/46] Move viewing action into template I forget about these things hehe --- app/controllers/admin-calendar.js | 8 +------- app/templates/admin-calendar.hbs | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/app/controllers/admin-calendar.js b/app/controllers/admin-calendar.js index 286d3c05..abed0206 100644 --- a/app/controllers/admin-calendar.js +++ b/app/controllers/admin-calendar.js @@ -1,9 +1,3 @@ import CalendarController from './calendar'; -export default CalendarController.extend({ - actions: { - setViewingSlot(slot) { - this.set('viewingSlot', slot); - } - } -}); +export default CalendarController.extend(); diff --git a/app/templates/admin-calendar.hbs b/app/templates/admin-calendar.hbs index e1e6cc3d..3cc63f07 100644 --- a/app/templates/admin-calendar.hbs +++ b/app/templates/admin-calendar.hbs @@ -9,7 +9,7 @@ {{#calendar.days showDaysAround=false as |day|}} - {{calendar-day day=day slots=slots count=true setViewingSlot=(action 'setViewingSlot')}} + {{calendar-day day=day slots=slots count=true setViewingSlot=(action (mut viewingSlot))}} {{/calendar.days}} {{/power-calendar}} From 48ebcfacbbab704f77a1303d76e94dbaece06aff Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 5 Jan 2018 05:17:05 -0600 Subject: [PATCH 45/46] Remove fake slots --- app/routes/calendar.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/routes/calendar.js b/app/routes/calendar.js index 8c90e55f..b9e8ab3f 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -37,11 +37,7 @@ export default Route.extend({ throw new Error('We were unable to log you in with that token.'); }).then(person => { return RSVP.hash({ - slots: this.store.findAll('slot').catch(() => [ - this.store.createRecord('slot', {start: new Date(2017, 11, 3, 17), end: new Date(2017, 11, 3, 21), count: 2}), - this.store.createRecord('slot', {start: new Date(2017, 11, 3, 11), end: new Date(2017, 11, 3, 17), count: 3}), - this.store.createRecord('slot', {start: new Date(2017, 11, 8, 17), count: 4}) - ]), + slots: this.store.findAll('slot'), person, month }); From 70f066caae071d1494fb7654a6ba5484e919f847 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 5 Jan 2018 05:39:06 -0600 Subject: [PATCH 46/46] Update appearance of calendar session --- app/templates/calendar.hbs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/templates/calendar.hbs b/app/templates/calendar.hbs index 4a81256c..3e2b2b03 100644 --- a/app/templates/calendar.hbs +++ b/app/templates/calendar.hbs @@ -1,6 +1,10 @@ -
    You are logged in as {{person.email}}
    - {{#power-calendar center=month daysComponent='calendar-days' as |calendar|}} + {{#paper-card as |card|}} + {{#card.content}} +
    You are logged in as {{person.email}}
    + {{/card.content}} + {{/paper-card}} + {{calendar.nav}} {{#calendar.days showDaysAround=false as |day|}}