diff --git a/.travis.yml b/.travis.yml index de8dc13..ea1b929 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,17 +3,11 @@ branches: only: - master node_js: - - "9" -sudo: required -dist: trusty -addons: - chrome: stable + - '6' +sudo: false cache: directories: - "$HOME/.npm" -env: - global: - - JOBS=1 before_install: - npm config set spin false - npm install -g phantomjs-prebuilt diff --git a/README.md b/README.md index 4a9360d..a69437b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ You will need the following things properly installed on your computer. * [Git](https://git-scm.com/) * [Node.js](https://nodejs.org/) (with NPM) * [Ember CLI](https://ember-cli.com/) -* [Google Chrome](https://google.com/chrome/) +* [PhantomJS](http://phantomjs.org/) ## Installation diff --git a/app/adapters/application.js b/app/adapters/application.js index a9c6c0c..65c8c47 100644 --- a/app/adapters/application.js +++ b/app/adapters/application.js @@ -9,11 +9,4 @@ export default JSONAPIAdapter.extend(DataAdapterMixin, { namespace: API_NAMESPACE, host: API_HOST, authorizer: 'authorizer:application', - // DRF-JSON-API returns 400 by default - handleResponse(status, headers, payload) { - if (status === 400 && payload.errors) { - return new DS.InvalidError(payload.errors); - } - return this._super(...arguments); - } }); diff --git a/app/adapters/datasheet-attachment.js b/app/adapters/datasheet-attachment.js deleted file mode 100644 index a89c329..0000000 --- a/app/adapters/datasheet-attachment.js +++ /dev/null @@ -1,19 +0,0 @@ -import ApplicationAdapter from './application'; -import FileUploadAdapter from 'ccdb-web/mixins/file-upload'; - -export default ApplicationAdapter.extend(FileUploadAdapter, { - getFormFields(data) { - return { - 'datasheet': data['data']['attributes']['datasheet'], - 'collection': JSON.stringify(data['data']['relationships']['collection']['data']), - } - }, - - getFormKey(key) { - return key; - }, - - getFormValue(key, value) { - return value; - }, -}); diff --git a/app/app.js b/app/app.js index b3b2bd6..f796e79 100644 --- a/app/app.js +++ b/app/app.js @@ -1,9 +1,11 @@ -import Application from '@ember/application'; +import Ember from 'ember'; import Resolver from './resolver'; import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; -const App = Application.extend({ +let App; + +App = Ember.Application.extend({ modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix, Resolver diff --git a/app/authenticators/application.js b/app/authenticators/application.js index 075eeff..3ae0d7d 100644 --- a/app/authenticators/application.js +++ b/app/authenticators/application.js @@ -1,11 +1,9 @@ -import { Promise } from 'rsvp'; -import $ from 'jquery'; -import { get } from '@ember/object'; -import { isEmpty } from '@ember/utils'; -import { run } from '@ember/runloop'; +import Ember from 'ember'; import BaseAuthenticator from 'ember-simple-auth/authenticators/base'; import config from '../config/environment'; +const { RSVP: { Promise }, $, get, isEmpty, run } = Ember; + export default BaseAuthenticator.extend({ serverTokenEndpoint: `${config.APP.API_HOST}/api/auth/login/`, tokenAttributeName: 'data.attributes.auth-token', diff --git a/app/authorizers/application.js b/app/authorizers/application.js index 740f446..b8c154c 100644 --- a/app/authorizers/application.js +++ b/app/authorizers/application.js @@ -1,7 +1,8 @@ -import { isEmpty } from '@ember/utils'; -import { get } from '@ember/object'; +import Ember from 'ember'; import BaseAuthorizer from 'ember-simple-auth/authorizers/base'; +const { isEmpty, get } = Ember; + export default BaseAuthorizer.extend({ authorize(data, block) { const accessToken = get(data, 'data.attributes.auth-token'); diff --git a/app/components/action-button.js b/app/components/action-button.js deleted file mode 100644 index 061b53b..0000000 --- a/app/components/action-button.js +++ /dev/null @@ -1,40 +0,0 @@ -import Component from '@ember/component'; - -export default Component.extend({ - tagName: 'a', - classNames: ['btn'], - classNameBindings: [ - // Styles - 'isDefault:btn-default', - 'isPrimary:btn-primary', - 'isSuccess:btn-success', - 'isInfo:btn-info', - 'isWarning:btn-warning', - 'isDanger:btn-danger', - 'isLink:btn-link', - // Sizes - 'isLarge:btn-lg', - 'isSmall:btn-sm', - 'isXSmall:btn-xs', - ], - - // ARGS - // Styles - isDefault: false, - isPrimary: false, - isSuccess: false, - isInfo: false, - isWarning: false, - isDanger: false, - isLink: false, - // Sizes - isLarge: false, - isSmall: false, - isXSmall: false, - - label: 'LABEL', - - click() { - this.get('onClick')(); - } -}); diff --git a/app/components/admin-section-list.js b/app/components/admin-section-list.js index 5570647..00d6fa3 100644 --- a/app/components/admin-section-list.js +++ b/app/components/admin-section-list.js @@ -1,3 +1,5 @@ -import Component from '@ember/component'; +import Ember from 'ember'; + +const { Component } = Ember; export default Component.extend({}); diff --git a/app/components/ccdb-filter.js b/app/components/ccdb-filter.js deleted file mode 100644 index db2ed63..0000000 --- a/app/components/ccdb-filter.js +++ /dev/null @@ -1,3 +0,0 @@ -import Component from '@ember/component'; - -export default Component.extend({ }); diff --git a/app/components/ccdb-pagination.js b/app/components/ccdb-pagination.js index 233ca4c..1ef4a00 100644 --- a/app/components/ccdb-pagination.js +++ b/app/components/ccdb-pagination.js @@ -1,41 +1,5 @@ -import Component from '@ember/component'; -import { alias } from '@ember/object/computed'; -import { computed } from '@ember/object'; +import Ember from 'ember'; -export default Component.extend({ - // ARGS - model: null, - - // COMPUTED - meta: alias('model.meta'), - links: alias('meta.links'), - - currentPage: alias('meta.pagination.page'), - totalRecords: alias('meta.pagination.count'), - - firstLink: alias('links.first'), - lastLink: alias('links.last'), - nextLink: alias('links.next'), - prevLink: alias('links.prev'), - - _getPage(link) { - link = this.get(link); - if (link === null) { - return null; - } - const url = new URL(link); - return parseInt(url.searchParams.get('page')); - }, - - _notEqual(a, b) { - return this.get(a) !== this.get(b); - }, - - first: computed('firstLink', function() { return this._getPage('firstLink'); }), - last: computed('lastLink', function() { return this._getPage('lastLink'); }), - next: computed('nextLink', function() { return this._getPage('nextLink'); }), - prev: computed('prevLink', function() { return this._getPage('prevLink'); }), - - notOnFirst: computed('first', 'currentPage', function() { return this._notEqual('first', 'currentPage'); }), - notOnLast: computed('last', 'currentPage', function() { return this._notEqual('last', 'currentPage'); }), +export default Ember.Component.extend({ + classNames: ['row'], }); diff --git a/app/components/ccdb-table.js b/app/components/ccdb-table.js index 8aade24..fce3474 100644 --- a/app/components/ccdb-table.js +++ b/app/components/ccdb-table.js @@ -1,13 +1,16 @@ -import Component from '@ember/component'; +import Ember from 'ember'; import Table from 'ember-light-table'; +const { Component } = Ember; + export default Component.extend({ - // ARGS model: null, columns: null, - table: null, - didReceiveAttrs() { + + classNames: ['row'], + + init() { this._super(...arguments); const table = new Table(this.get('columns'), this.get('model')); this.set('table', table); diff --git a/app/components/collection/create-container.js b/app/components/collection/create-container.js deleted file mode 100644 index fd599fa..0000000 --- a/app/components/collection/create-container.js +++ /dev/null @@ -1,93 +0,0 @@ -import { getProperties, set } from '@ember/object'; -import Component from '@ember/component'; -import { inject as service } from '@ember/service'; -import { debounce } from '@ember/runloop'; -import RSVP from 'rsvp'; -import Changeset from 'ember-changeset'; -import lookupValidator from 'ember-changeset-validations'; -import config from 'ccdb-web/config/environment'; - -export default Component.extend({ - store: service(), - - init() { - this._super(...arguments); - const model = this.get('model'); - const validations = this.get('validations'); - const hasMany = this.get('hasMany'); - - let changesets = {}; - changesets['new'] = []; - changesets['delete'] = []; - changesets['hasMany'] = {}; - changesets['model'] = new Changeset(model, - lookupValidator(validations['collection']), - validations['collection']); - - hasMany.forEach((hasMany) => { - let relatedChangesets = []; - let validation = validations[hasMany]; - const related = model.get(hasMany); - related.forEach((r) => { - const changeset = new Changeset(r, lookupValidator(validation), - validation); - relatedChangesets.push({ model: r, changeset: changeset }); - }); - changesets['hasMany'][hasMany] = relatedChangesets; - }); - - this.set('changesets', changesets); - this.set('newStudyLocationAdmin', `${config.APP.API_HOST}/admin/locations/studylocation/add/`); - }, - - actions: { - addHasMany(modelName, relatedName) { - const store = this.get('store'); - let changesets = this.get('changesets'); - const validations = this.get('validations'); - const validation = validations[relatedName]; - const model = this.get('model'); - const related = store.createRecord(modelName, { collection: model }); - model.get(relatedName).pushObject(related); - changesets['new'].pushObject(related); - const changeset = new Changeset(related, lookupValidator(validation), validation); - changesets['hasMany'][relatedName].pushObject({ model: related, changeset: changeset }); - }, - - deleteHasMany(changesetRecord, relatedName) { - let changesets = this.get('changesets'); - changesets['delete'].pushObject(changesetRecord.model); - changesets['hasMany'][relatedName].removeObject(changesetRecord); - }, - - // Gross, this side-effects by saving immediately. Someday I should clean - // this up, but for now, you have been warned. - addOption(relatedModelName, optionName, collectionAttrName, relatedAttrName, term) { - const props = getProperties(this, 'store', 'options', 'changesets'); - const { store, options, changesets: { model } } = props; - let payload = {}; - payload[relatedAttrName] = term; - const record = store.createRecord(relatedModelName, payload) - record.save().then((record) => { - set(options, optionName, store.peekAll(relatedModelName)); - set(model, collectionAttrName, record); - }); - }, - - updateDatasheet(changeset, event) { - changeset.set('datasheet', event.target.files[0]); - }, - - searchStudyLocation(term) { - return new RSVP.Promise((resolve, reject) => { - debounce(this, this._performSearch, 'study-location', { page_size: 500, code: term }, resolve, reject, 400); - }); - }, - }, - - _performSearch(model, payload, resolve, reject) { - this.get('store').query(model, payload).then((results) => { - resolve(results); - }, reject); - }, -}); diff --git a/app/components/collection/detail-container.js b/app/components/collection/detail-container.js deleted file mode 100644 index 66f9ba1..0000000 --- a/app/components/collection/detail-container.js +++ /dev/null @@ -1,34 +0,0 @@ -import Component from '@ember/component'; - -export default Component.extend({ - // ARGS - model: null, - - mainColumns: [ - { label: 'Project', valuePath: 'project.name', }, - { label: 'IACUC', valuePath: 'project.iacucNumber', }, - { label: 'Region', valuePath: 'studyLocation.site.region.name', }, - { label: 'Site', valuePath: 'studyLocation.site.name', }, - { label: 'Study Location', valuePath: 'studyLocation.code', }, - { label: 'Method', valuePath: 'collectionMethod.code', }, - { label: 'Type', valuePath: 'collectionType.name', }, - { label: '# of Traps', valuePath: 'numberOfTraps', }, - { label: 'Start', valuePath: 'startDateTime', }, - { label: 'End', valuePath: 'endDateTime', }, - { label: 'ADFG Permit', valuePath: 'adfgPermit.name', }, - ], - - collectionSpeciesColumns: [ - { label: 'Species', valuePath: 'species.commonName' }, - { label: 'Count', valuePath: 'count' }, - { label: 'Count Estimated?', valuePath: 'countEstimated' }, - { label: 'Sex', valuePath: 'sex.name' }, - ], - - envMeasColumns: [ - { label: 'Date Measured', valuePath: 'dateMeasured', }, - { label: 'Time Measured', valuePath: 'timeMeasured', }, - { label: 'Water Temp (deg C)', valuePath: 'waterTempC', }, - { label: 'Air Temp (deg C)', valuePath: 'airTempC', }, - ], -}); diff --git a/app/components/collection/list-container.js b/app/components/collection/list-container.js deleted file mode 100644 index 184a11d..0000000 --- a/app/components/collection/list-container.js +++ /dev/null @@ -1,20 +0,0 @@ -import Component from '@ember/component'; - -export default Component.extend({ - // ARGS - model: null, - - columns: [ - { label: 'Project', valuePath: 'project.name', }, - { label: 'IACUC', valuePath: 'project.iacucNumber', }, - { label: 'Species', valuePath: 'speciesAndCounts', }, - { label: 'Region', valuePath: 'studyLocation.site.region.name', }, - { label: 'Site', valuePath: 'studyLocation.site.name', }, - { label: 'Study Location', valuePath: 'studyLocation.code', }, - { label: 'Method', valuePath: 'collectionMethod.name', }, - { label: '# of Traps', valuePath: 'numberOfTraps', }, - { label: 'Start', valuePath: 'startDateTime', }, - { label: 'End', valuePath: 'endDateTime', }, - { label: 'ADFG Permit', valuePath: 'adfgPermit.name', }, - ], -}); diff --git a/app/components/collections-container.js b/app/components/collections-container.js new file mode 100644 index 0000000..376c977 --- /dev/null +++ b/app/components/collections-container.js @@ -0,0 +1,15 @@ +import Ember from 'ember'; + +const { Component } = Ember; + +export default Component.extend({ + columns: [ + { label: 'Project', valuePath: 'project.name', }, + { label: 'Study Location', valuePath: 'studyLocation.code', }, + { label: 'Method', valuePath: 'collectionMethod.code', }, + { label: 'Type', valuePath: 'collectionType.name', }, + { label: '# of Traps', valuePath: 'numberOfTraps', }, + { label: 'Start', valuePath: 'startDateTime', }, + { label: 'End', valuePath: 'endDateTime', }, + ], +}); diff --git a/app/components/confirm-button.js b/app/components/confirm-button.js deleted file mode 100644 index 89e921a..0000000 --- a/app/components/confirm-button.js +++ /dev/null @@ -1,23 +0,0 @@ -import Component from '@ember/component'; - -export default Component.extend({ - tagName: 'span', - showConfirm: false, - initialLabel: 'LABEL', - confirmLabel: 'CONFIRM LABEL', - cancelLabel: 'Cancel', - - actions: { - initial() { - this.set('showConfirm', true); - }, - - cancel() { - this.set('showConfirm', false); - }, - - confirm() { - this.get('onClick')(); - }, - }, -}); diff --git a/app/components/crud-form.js b/app/components/crud-form.js deleted file mode 100644 index 889c937..0000000 --- a/app/components/crud-form.js +++ /dev/null @@ -1,6 +0,0 @@ -import Component from '@ember/component'; - -export default Component.extend({ - // ARGS - changesets: null, -}); diff --git a/app/components/filter-collections.js b/app/components/filter-collections.js new file mode 100644 index 0000000..16e66b5 --- /dev/null +++ b/app/components/filter-collections.js @@ -0,0 +1,5 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + tagName: 'form', +}); diff --git a/app/components/form-content.js b/app/components/form-content.js deleted file mode 100644 index 9d2bc5a..0000000 --- a/app/components/form-content.js +++ /dev/null @@ -1,5 +0,0 @@ -import Component from '@ember/component'; - -export default Component.extend({ - tagName: 'form', -}); diff --git a/app/components/loading-spinner.js b/app/components/loading-spinner.js index 8ee064f..f65d12f 100644 --- a/app/components/loading-spinner.js +++ b/app/components/loading-spinner.js @@ -1,4 +1,6 @@ -import Component from '@ember/component'; +import Ember from 'ember'; + +const { Component } = Ember; export default Component.extend({ classNames: ['spinner'], diff --git a/app/components/validated-field.js b/app/components/validated-field.js deleted file mode 100644 index a505dcf..0000000 --- a/app/components/validated-field.js +++ /dev/null @@ -1,18 +0,0 @@ -import Component from '@ember/component'; -import { get, computed } from '@ember/object'; -import { isEmpty } from '@ember/utils'; - -export default Component.extend({ - classNames: ['form-group'], - classNameBindings: ['isValid::has-error'], - - isValid: computed('changeset.error', 'property', function() { - const changeset = this.get('changeset'); - const property = this.get('property'); - return isEmpty(get(changeset, `error.${property}`)); - }), - - hasLabel: computed('label', function() { - return !isEmpty(get(this, 'label')); - }), -}); diff --git a/app/controllers/application.js b/app/controllers/application.js index 5e8a1e1..59d2822 100644 --- a/app/controllers/application.js +++ b/app/controllers/application.js @@ -1,5 +1,6 @@ -import Controller from '@ember/controller'; -import { inject as service } from '@ember/service'; +import Ember from 'ember'; + +const { Controller, inject: { service }} = Ember; export default Controller.extend({ session: service('session'), diff --git a/app/controllers/collections/create.js b/app/controllers/collections/create.js deleted file mode 100644 index 9234268..0000000 --- a/app/controllers/collections/create.js +++ /dev/null @@ -1,46 +0,0 @@ -import Controller from '@ember/controller'; -import { computed } from '@ember/object'; -import CollectionValidations from 'ccdb-web/validations/collection'; -import CollectionSpeciesValidations from 'ccdb-web/validations/collection-species'; -import CollectionMeasurementValidations from 'ccdb-web/validations/collection-measurement'; -import DatasheetValidations from 'ccdb-web/validations/datasheet'; -import ValidationMixin from 'ccdb-web/mixins/validation'; - -export default Controller.extend(ValidationMixin, { - CollectionValidations, - CollectionSpeciesValidations, - DatasheetValidations, - CollectionMeasurementValidations, - - hasMany: ['collectionSpecies', 'datasheets', 'envMeasurements'], - - options: computed('projectOptions', 'studyLocationOptions', - 'collectionTypeOptions', 'collectionMethodOptions', - 'speciesOptions', 'adfgPermitOptions', 'sexOptions', - function() { - return { - projects: this.get('projectOptions'), - studyLocations: this.get('studyLocationOptions'), - collectionTypes: this.get('collectionTypeOptions'), - collectionMethods: this.get('collectionMethodOptions'), - species: this.get('speciesOptions'), - adfgPermits: this.get('adfgPermitOptions'), - sexes: this.get('sexOptions'), - }; - }), - - actions: { - onSave(changeset) { - const postSave = () => { this.transitionToRoute('collections.index'); }; - return this.transitionToRoute('loading').then(() => { - return this.validationSave(changeset, postSave); - }); - }, - onCancel(changeset) { - const postCancel = () => { this.transitionToRoute('collections.index'); }; - return this.transitionToRoute('loading').then(() => { - return this.validationCancel(changeset, postCancel); - }); - }, - }, -}); diff --git a/app/controllers/collections/detail/edit.js b/app/controllers/collections/detail/edit.js deleted file mode 100644 index 6133707..0000000 --- a/app/controllers/collections/detail/edit.js +++ /dev/null @@ -1,52 +0,0 @@ -import Controller from '@ember/controller'; -import { computed } from '@ember/object'; -import CollectionValidations from 'ccdb-web/validations/collection'; -import CollectionSpeciesValidations from 'ccdb-web/validations/collection-species'; -import CollectionMeasurementValidations from 'ccdb-web/validations/collection-measurement'; -import DatasheetValidations from 'ccdb-web/validations/datasheet'; -import ValidationMixin from 'ccdb-web/mixins/validation'; - -export default Controller.extend(ValidationMixin, { - CollectionValidations, - CollectionSpeciesValidations, - DatasheetValidations, - CollectionMeasurementValidations, - - hasMany: ['collectionSpecies', 'datasheets', 'envMeasurements'], - - options: computed('projectOptions', 'studyLocationOptions', - 'collectionTypeOptions', 'collectionMethodOptions', - 'speciesOptions', 'adfgPermitOptions', 'sexOptions', - function() { - return { - projects: this.get('projectOptions'), - studyLocations: this.get('studyLocationOptions'), - collectionTypes: this.get('collectionTypeOptions'), - collectionMethods: this.get('collectionMethodOptions'), - species: this.get('speciesOptions'), - adfgPermits: this.get('adfgPermitOptions'), - sexes: this.get('sexOptions'), - }; - }), - - actions: { - onSave(changesets) { - const postSave = () => { - // Use the model's ID here because of the ArrayProxy in the route - this.transitionToRoute('collections.detail', this.get('model.id')); - }; - return this.transitionToRoute('loading').then(() => { - return this.validationSave(changesets, postSave); - }); - }, - onCancel(changesets) { - const postCancel = () => { - // Use the model's ID here because of the ArrayProxy in the route - return this.transitionToRoute('collections.detail', this.get('model.id')); - }; - return this.transitionToRoute('loading').then(() => { - return this.validationCancel(changesets, postCancel); - }); - }, - }, -}); diff --git a/app/controllers/collections/detail/index.js b/app/controllers/collections/detail/index.js deleted file mode 100644 index e0bc42c..0000000 --- a/app/controllers/collections/detail/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import Controller from '@ember/controller'; - -export default Controller.extend({ - actions: { - editCollection() { - this.transitionToRoute('collections.detail.edit', this.get('model')); - }, - deleteCollection() { - this.get('model')[0].destroyRecord().then(() => { - this.transitionToRoute('collections'); - }); - }, - }, -}); diff --git a/app/controllers/collections/index.js b/app/controllers/collections/index.js deleted file mode 100644 index d4a8cdf..0000000 --- a/app/controllers/collections/index.js +++ /dev/null @@ -1,85 +0,0 @@ -import Controller from '@ember/controller'; -import { set, get, computed } from '@ember/object'; - - -export default Controller.extend({ - queryParams: ['page', 'project', 'region', 'site', 'study_location', - 'collection_method', 'number_of_traps', 'collection_start_date', - 'collection_end_date', 'adfg_permit', 'species'], - page: 1, - project: [], - region: [], - site: [], - study_location: [], - collection_method: [], - adfg_permit: [], - species: [], - number_of_traps: '', - collection_start_date: '', - collection_end_date: '', - - options: computed('projectOptions', 'regionOptions', 'siteOptions', - 'studyLocationOptions', 'collectionMethodOptions', - 'adfgPermitOptions', 'speciesOptions', function() { - return { - projects: this.get('projectOptions'), - regions: this.get('regionOptions'), - sites: this.get('siteOptions'), - studyLocations: this.get('studyLocationOptions'), - collectionMethods: this.get('collectionMethodOptions'), - adfgPermits: this.get('adfgPermitOptions'), - species: this.get('speciesOptions'), - }; - }), - - _coerceId(model) { - return +get(model, 'id'); - }, - - actions: { - changePage(page) { - this.set('page', page); - }, - rowClick(row) { - this.transitionToRoute('collections.detail', row.get('id')); - }, - createCollection() { - this.transitionToRoute('collections.create'); - }, - resetFilter() { - set(this, 'page', 1); - ['project', 'region', 'site', 'study_location', 'collection_method', - 'adfg_permit', 'species'].forEach((field) => { - set(this, field, []); - }); - ['number_of_traps', 'collection_start_date', 'collection_end_date'].forEach((field) => { - set(this, field, ''); - }); - }, - changeFilter(filter) { - // Need to reset the page so that things don't get weird - set(this, 'page', 1); - - const filterModelFields = ['project', 'region', 'site', 'study_location', - 'collection_method', 'adfg_permit', 'species']; - - filterModelFields.forEach((field) => { - let fields = get(filter, field); - fields = fields.map(this._coerceId); - set(this, field, fields); - }); - - set(this, 'number_of_traps', get(filter, 'number_of_traps')); - - ['collection_start_date', 'collection_end_date'].forEach((field) => { - let value = get(filter, field); - if (value) { - value = value.toJSON().split('T')[0]; - } else { - value = ''; - } - set(this, field, value); - }); - }, - }, -}); diff --git a/app/controllers/login.js b/app/controllers/login.js index 7311a02..e5bb9c8 100644 --- a/app/controllers/login.js +++ b/app/controllers/login.js @@ -1,5 +1,6 @@ -import Controller from '@ember/controller'; -import { inject as service } from '@ember/service'; +import Ember from 'ember'; + +const { Controller, inject: { service } } = Ember; export default Controller.extend({ session: service(), diff --git a/app/index.html b/app/index.html index edae105..e01418d 100644 --- a/app/index.html +++ b/app/index.html @@ -17,8 +17,8 @@ {{content-for "body"}} - - + + {{content-for "body-footer"}} diff --git a/app/mixins/file-upload.js b/app/mixins/file-upload.js deleted file mode 100644 index 5117782..0000000 --- a/app/mixins/file-upload.js +++ /dev/null @@ -1,62 +0,0 @@ -import Mixin from '@ember/object/mixin'; -import { isArray } from '@ember/array'; -const { keys } = Object; - -// Portions borrowed from https://github.com/funtusov/ember-cli-form-data -// (that project has an MIT license listed, but no copyright holder explicitly identified) -export default Mixin.create({ - formDataTypes: ['POST', 'PUT', 'PATCH'], - - ajaxOptions(url, type, options) { - let data; - if (options && 'data' in options) { data = options.data; } - let hash = this._super.apply(this, arguments); - - if (typeof FormData !== 'undefined' && data && this.formDataTypes.indexOf(type) >= 0) { - hash.processData = false; - hash.contentType = false; - hash.data = this._getFormData(data); - } - return hash; - }, - - getFormFields(data) { - this._root = this._root || keys(data)[0]; - return data[this._root]; - }, - - getFormKey(key) { - return `${this._root}[${key}]`; - }, - - getFormValue(key, value) { - return value; - }, - - _getFormData(data) { - let formData = new FormData(); - const fields = this.getFormFields(data); - - keys(fields).forEach((key) => { - this._appendValue( - this.getFormValue(key, fields[key]), - this.getFormKey(key, fields[key]), - formData); - }); - return formData; - }, - - _appendValue(value, formKey, formData) { - if (isArray(value)) { - value.forEach((item) => { - this._appendValue(item, `${formKey}[]`, formData); - }); - } else if (value && value.constructor === Object) { - keys(value).forEach((key) => { - this._appendValue(value[key], `${formKey}[${key}]`, formData); - }); - } else if (typeof value !== 'undefined'){ - formData.append(formKey, value === null ? '' : value); - } - }, -}); diff --git a/app/mixins/validation.js b/app/mixins/validation.js deleted file mode 100644 index 7e8c1cf..0000000 --- a/app/mixins/validation.js +++ /dev/null @@ -1,73 +0,0 @@ -import Mixin from '@ember/object/mixin'; -import { get } from '@ember/object'; -import RSVP from 'rsvp'; -const { keys } = Object; - -export default Mixin.create({ - validationSave(changesets, postSave) { - let promises = [], changes = [], saves = [], isValid = true; - - let modelChangeset = changesets['model']; - - // first, delete anything that needs to be removed - for (const model of changesets['delete']) { - promises.push(model.destroyRecord()); - } - - // second, handle changes on parent model (this is important if new) - modelChangeset.validate().then(() => { - if (modelChangeset.get('isValid')) { - return modelChangeset.save(); - } - }).then(() => { - for (const hasMany of keys(changesets['hasMany'])) { - for (const { changeset } of changesets['hasMany'][hasMany]) { - promises.push(changeset.validate()); - changes.push(changeset); - } - } - return RSVP.all(promises); - }).then(() => { // don't need the promises, just that they are done. - for (let changeset of changes) { - if (get(changeset, 'isValid')) { - let saver = changeset.save().catch((error) => { - /* eslint-disable no-console */ - console.log(error); - /* eslint-enable no-console */ - // TODO: do something with server-side non-attr errors - }); - saves.push(saver); - } else { - isValid = false; - } - } - return RSVP.all(saves); - }).then(() => { - if (isValid) { return postSave(); } - }); - }, - - validationCancel(changesets, postCancel) { - delete changesets['delete']; - for (const key of keys(changesets)) { - if (key === 'new') { - for (const model of changesets[key]) { - model.destroyRecord(); - } - } else if (key === 'hasMany') { - const hasMany = changesets[key]; - for (const hasManyKey of keys(changesets[key])) { - const hasManyChangesets = hasMany[hasManyKey]; - for (const changeset of hasManyChangesets) { - changeset.rollback(); - } - } - } else { // single - const changeset = changesets[key]; - changeset.rollback(); - } - } - - return postCancel(); - }, -}); diff --git a/app/models/adfg-permit.js b/app/models/adfg-permit.js deleted file mode 100644 index de48a20..0000000 --- a/app/models/adfg-permit.js +++ /dev/null @@ -1,10 +0,0 @@ -import DS from 'ember-data'; - -const { Model, attr, hasMany } = DS; - -export default Model.extend({ - name: attr('string'), - sortOrder: attr('number'), - - collection: hasMany('collection'), -}); diff --git a/app/models/collection-measurement.js b/app/models/collection-measurement.js deleted file mode 100644 index 41eef75..0000000 --- a/app/models/collection-measurement.js +++ /dev/null @@ -1,12 +0,0 @@ -import DS from 'ember-data'; - -const { Model, attr, belongsTo } = DS; - -export default Model.extend({ - dateMeasured: attr('ccdb-date'), - timeMeasured: attr('string'), - waterTempC: attr('number'), - airTempC: attr('number'), - - collection: belongsTo('collection'), -}); diff --git a/app/models/collection-species.js b/app/models/collection-species.js deleted file mode 100644 index 5839d7c..0000000 --- a/app/models/collection-species.js +++ /dev/null @@ -1,12 +0,0 @@ -import DS from 'ember-data'; - -const { Model, attr, belongsTo } = DS; - -export default Model.extend({ - sex: belongsTo('sex'), - count: attr('number'), - countEstimated: attr('boolean', { defaultValue: false }), - - collection: belongsTo('collection'), - species: belongsTo('species'), -}); diff --git a/app/models/collection.js b/app/models/collection.js index 05c90fd..c2fc7c9 100644 --- a/app/models/collection.js +++ b/app/models/collection.js @@ -1,41 +1,21 @@ -import { mapBy } from '@ember/object/computed'; -import { computed } from '@ember/object'; +import Ember from 'ember'; import DS from 'ember-data'; -const { Model, attr, belongsTo, hasMany } = DS; +const { computed } = Ember; +const { Model, attr, belongsTo } = DS; export default Model.extend({ displayName: attr('string'), numberOfTraps: attr('number'), - collectionStartDate: attr('ccdb-date'), + collectionStartDate: attr('string-null-to-empty'), collectionStartTime: attr('string-null-to-empty'), - collectionEndDate: attr('ccdb-date'), + collectionEndDate: attr('string-null-to-empty'), collectionEndTime: attr('string-null-to-empty'), - notes: attr('string', { defaultValue: '' }), - project: belongsTo('project'), - studyLocation: belongsTo('study-location'), - collectionMethod: belongsTo('collection-method'), - collectionType: belongsTo('collection-type'), - adfgPermit: belongsTo('adfg-permit'), - - collectionSpecies: hasMany('collection-species'), - datasheets: hasMany('datasheet-attachment'), - envMeasurements: hasMany('collection-measurement'), - - // computed - species: mapBy('collectionSpecies', 'species'), - - speciesNames: mapBy('species', 'commonName'), - - counts: mapBy('collectionSpecies', 'count'), - - speciesAndCounts: computed('speciesNames', 'counts', function() { - const speciesNames = this.get('speciesNames'); - let counts = this.get('counts'); - counts = counts.map(c => c !== null ? c : 'No Count'); - return speciesNames.map((n, i) => `${n} (${counts[i]})`).join(', '); - }), + project: belongsTo('project'), + studyLocation: belongsTo('study-location'), + collectionMethod: belongsTo('collection-method'), + collectionType: belongsTo('collection-type'), startDateTime: computed('collectionStartDate', 'collectionStartTime', function() { return this._mergeDateTime('Start'); }), diff --git a/app/models/datasheet-attachment.js b/app/models/datasheet-attachment.js deleted file mode 100644 index 2c02202..0000000 --- a/app/models/datasheet-attachment.js +++ /dev/null @@ -1,9 +0,0 @@ -import DS from 'ember-data'; - -const { Model, attr, belongsTo } = DS; - -export default Model.extend({ - datasheet: attr('file'), - - collection: belongsTo('collection'), -}); diff --git a/app/models/region.js b/app/models/region.js deleted file mode 100644 index 3530700..0000000 --- a/app/models/region.js +++ /dev/null @@ -1,11 +0,0 @@ -import DS from 'ember-data'; - -const { Model, attr, hasMany } = DS; - -export default Model.extend({ - name: attr('string'), - code: attr('string'), - sortOrder: attr('number'), - - site: hasMany('site'), -}); diff --git a/app/models/sex.js b/app/models/sex.js deleted file mode 100644 index 6f3b265..0000000 --- a/app/models/sex.js +++ /dev/null @@ -1,8 +0,0 @@ -import DS from 'ember-data'; - -const { Model, attr } = DS; - -export default Model.extend({ - name: attr('string'), - sortOrder: attr('number'), -}); diff --git a/app/models/site.js b/app/models/site.js deleted file mode 100644 index 04402e7..0000000 --- a/app/models/site.js +++ /dev/null @@ -1,13 +0,0 @@ -import DS from 'ember-data'; - -const { Model, attr, hasMany, belongsTo } = DS; - -export default Model.extend({ - name: attr('string'), - code: attr('string'), - description: attr('string'), - sortOrder: attr('number'), - - region: belongsTo('region'), - studyLocation: hasMany('study-location'), -}); diff --git a/app/models/species.js b/app/models/species.js deleted file mode 100644 index e66c4f9..0000000 --- a/app/models/species.js +++ /dev/null @@ -1,11 +0,0 @@ -import DS from 'ember-data'; - -const { Model, attr } = DS; - -export default Model.extend({ - commonName: attr('string'), - genus: attr('string'), - species: attr('string'), - parasite: attr('boolean'), - sortOrder: attr('number'), -}); diff --git a/app/models/study-location.js b/app/models/study-location.js index 28969aa..7568218 100644 --- a/app/models/study-location.js +++ b/app/models/study-location.js @@ -1,6 +1,6 @@ import DS from 'ember-data'; -const { Model, attr, belongsTo } = DS; +const { Model, attr } = DS; export default Model.extend({ name: attr('string'), @@ -10,6 +10,4 @@ export default Model.extend({ collectingLocation: attr('string'), description: attr('string'), sortOrder: attr('number'), - - site: belongsTo('site'), }); diff --git a/app/router.js b/app/router.js index af47bd2..03cadfc 100644 --- a/app/router.js +++ b/app/router.js @@ -1,7 +1,7 @@ -import EmberRouter from '@ember/routing/router'; +import Ember from 'ember'; import config from './config/environment'; -const Router = EmberRouter.extend({ +const Router = Ember.Router.extend({ location: config.locationType, rootURL: config.rootURL }); @@ -10,10 +10,8 @@ Router.map(function() { this.route('login'); this.route('logout'); this.route('collections', function() { - this.route('create'); - this.route('detail', { path: '/:collection_id' }, function() { - this.route('edit'); - }); + this.route('1'); + this.route('new'); }); }); diff --git a/app/routes/application.js b/app/routes/application.js index b83c2c8..38bb6b3 100644 --- a/app/routes/application.js +++ b/app/routes/application.js @@ -1,4 +1,6 @@ -import Route from '@ember/routing/route'; +import Ember from 'ember'; import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin'; +const { Route } = Ember; + export default Route.extend(ApplicationRouteMixin, {}); diff --git a/app/routes/collections/1.js b/app/routes/collections/1.js new file mode 100644 index 0000000..26d9f31 --- /dev/null +++ b/app/routes/collections/1.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ +}); diff --git a/app/routes/collections/create.js b/app/routes/collections/create.js deleted file mode 100644 index 4c0ba55..0000000 --- a/app/routes/collections/create.js +++ /dev/null @@ -1,23 +0,0 @@ -import Route from '@ember/routing/route'; -import RSVP from 'rsvp'; - -export default Route.extend({ - model() { - const store = this.get('store'); - return RSVP.hash({ - model: store.createRecord('collection'), - projectOptions: store.findAll('project'), - studyLocationOptions: store.query('study-location', { page_size: 500 }), - collectionTypeOptions: store.findAll('collection-type'), - collectionMethodOptions: store.findAll('collection-method'), - speciesOptions: store.query('species', { page_size: 500 }), - adfgPermitOptions: store.findAll('adfg-permit'), - sexOptions: store.findAll('sex'), - }); - }, - - setupController(controller, models) { - this._super(...arguments); - controller.setProperties(models); - }, -}); diff --git a/app/routes/collections/detail.js b/app/routes/collections/detail.js deleted file mode 100644 index 354115c..0000000 --- a/app/routes/collections/detail.js +++ /dev/null @@ -1,12 +0,0 @@ -import Route from '@ember/routing/route'; -import RSVP from 'rsvp'; - -export default Route.extend({ - model(params) { - return RSVP.all([ - this.get('store').findRecord('collection', params.collection_id, { - include: 'collection-species,datasheets,env-measurements', - }) - ]); - }, -}); diff --git a/app/routes/collections/detail/edit.js b/app/routes/collections/detail/edit.js deleted file mode 100644 index 21a6bd4..0000000 --- a/app/routes/collections/detail/edit.js +++ /dev/null @@ -1,26 +0,0 @@ -import Route from '@ember/routing/route'; -import RSVP from 'rsvp'; - -export default Route.extend({ - model() { - const store = this.get('store'); - const model = this.modelFor('collections.detail'); - return RSVP.hash({ - model: model, - projectOptions: store.findAll('project'), - studyLocationOptions: store.query('study-location', { page_size: 500 }), - collectionTypeOptions: store.findAll('collection-type'), - collectionMethodOptions: store.findAll('collection-method'), - speciesOptions: store.query('species', { page_size: 500 }), - adfgPermitOptions: store.findAll('adfg-permit'), - sexOptions: store.findAll('sex'), - }); - }, - - setupController(controller, models) { - this._super(...arguments); - // Unwrap the parent route's listified model - models.model = models.model[0]; - controller.setProperties(models); - }, -}); diff --git a/app/routes/collections/index.js b/app/routes/collections/index.js index 2f65aba..9b3a78a 100644 --- a/app/routes/collections/index.js +++ b/app/routes/collections/index.js @@ -1,96 +1,11 @@ -import Route from '@ember/routing/route'; -import RSVP from 'rsvp'; +import Ember from 'ember'; + +const { Route } = Ember; export default Route.extend({ - queryParams: { - // qps are snake_case for the django api - page: { refreshModel: true }, - project: { refreshModel: true }, - region: { refreshModel: true }, - site: { refreshModel: true }, - study_location: { refreshModel: true }, - collection_method: { refreshModel: true }, - number_of_traps: { refreshModel: true }, - collection_start_date: { refreshModel: true }, - collection_end_date: { refreshModel: true }, - adfg_permit: { refreshModel: true }, - species: { refreshModel: true }, - }, - - model(params) { - const store = this.get('store'); - const includes = ['project', 'study-location', 'study-location.site', 'site', - 'collection-method', 'adfg-permit', 'collection-species', 'collection-species.species']; - const opts = { - include: includes.join(','), - }; - - return RSVP.hash({ - projectOptions: store.findAll('project'), - regionOptions: store.findAll('region'), - siteOptions: store.findAll('site'), - studyLocationOptions: store.query('study-location', { page_size: 500 }), - collectionMethodOptions: store.findAll('collection-method'), - adfgPermitOptions: store.findAll('adfg-permit'), - speciesOptions: store.query('species', { page_size: 500 }), - model: store.query('collection', Object.assign(params, opts)), + model() { + return this.get('store').findAll('collection', { + include: 'project,study-location,collection-method,collection-type' }); - }, - - setupController(controller, models) { - this._super(...arguments); - controller.setProperties(models); - - const store = this.get('store'); - - /* eslint-disable no-console */ - - let project = controller.get('project'); - console.log('project', project); - project = project.map(id => store.peekRecord('project', id)); - - let region = controller.get('region'); - console.log('region', region); - region = region.map(id => store.peekRecord('region', id)); - - let site = controller.get('site'); - console.log('site', site); - site = site.map(id => store.peekRecord('site', id)); - - let studyLocation = controller.get('study_location'); - console.log('studyLocation', studyLocation); - studyLocation = studyLocation.map(id => store.peekRecord('study-location', id)); - - let collectionMethod = controller.get('collection_method'); - console.log('collectionMethod', collectionMethod); - collectionMethod = collectionMethod.map(id => store.peekRecord('collection-method', id)); - - let adfgPermit = controller.get('adfg_permit'); - console.log('adfgPermit', adfgPermit); - adfgPermit = adfgPermit.map(id => store.peekRecord('adfg-permit', id)); - - let species = controller.get('species'); - console.log('species', species); - species = species.map(id => store.peekRecord('species', id)); - - /* eslint-enable no-console */ - - const numberOfTraps = controller.get('number_of_traps'); - const collectionStartDate = controller.get('collection_start_date'); - const collectionEndDate = controller.get('collection_end_date'); - - let filter = { - project, - region, - site, - study_location: studyLocation, - collection_method: collectionMethod, - number_of_traps: numberOfTraps, - collection_start_date: collectionStartDate, - collection_end_date: collectionEndDate, - adfg_permit: adfgPermit, - species, - } - controller.set('filters', filter); - }, + } }); diff --git a/app/routes/collections/new.js b/app/routes/collections/new.js new file mode 100644 index 0000000..26d9f31 --- /dev/null +++ b/app/routes/collections/new.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ +}); diff --git a/app/routes/index.js b/app/routes/index.js index 6d9dcb7..ed916b6 100644 --- a/app/routes/index.js +++ b/app/routes/index.js @@ -1,8 +1,6 @@ -import Route from '@ember/routing/route'; +import Ember from 'ember'; import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin'; -export default Route.extend(AuthenticatedRouteMixin, { - afterModel() { - this.transitionTo('collections'); - }, -}); +const { Route } = Ember; + +export default Route.extend(AuthenticatedRouteMixin, {}); diff --git a/app/routes/login.js b/app/routes/login.js index e05233c..a9687fd 100644 --- a/app/routes/login.js +++ b/app/routes/login.js @@ -1,4 +1,6 @@ -import Route from '@ember/routing/route'; +import Ember from 'ember'; import UnauthenticatedRouteMixin from 'ember-simple-auth/mixins/unauthenticated-route-mixin'; +const { Route } = Ember; + export default Route.extend(UnauthenticatedRouteMixin, {}); diff --git a/app/routes/logout.js b/app/routes/logout.js index 0056d12..c83dc10 100644 --- a/app/routes/logout.js +++ b/app/routes/logout.js @@ -1,5 +1,6 @@ -import Route from '@ember/routing/route'; -import { inject as service } from '@ember/service'; +import Ember from 'ember'; + +const { Route, inject: { service }} = Ember; export default Route.extend({ session: service('session'), diff --git a/app/serializers/application.js b/app/serializers/application.js deleted file mode 100644 index d8d8701..0000000 --- a/app/serializers/application.js +++ /dev/null @@ -1,16 +0,0 @@ -import { capitalize } from '@ember/string'; -import DS from 'ember-data'; - -const { JSONAPISerializer } = DS; - -export default JSONAPISerializer.extend({ - payloadTypeFromModelName(modelName) { - return modelName.split('-').map(key => capitalize(key)).join(''); - }, - - normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) { - let normalizedDocument = this._super(store, primaryModelClass, payload, id, requestType); - normalizedDocument.meta.links = normalizedDocument.links; - return normalizedDocument; - }, -}); diff --git a/app/styles/app.css b/app/styles/app.css index 1a2d097..b74ca4b 100644 --- a/app/styles/app.css +++ b/app/styles/app.css @@ -1,13 +1,12 @@ -[data-ember-action]:not(:disabled) { - cursor: pointer; +.content { + padding-left: 40px; + padding-right: 40px; + padding-top: 20px; + padding-bottom: 20px; } -.table-nav .pager { - margin-top: 10px; -} - -.table-stats { - margin-top: 10px; +.top-buffer { + padding-top: 20px; } .form-signin { @@ -50,10 +49,6 @@ border-top-right-radius: 0; } -.top-buffer { - margin-top: 20px; -} - /* Sidebar */ .sidebar { position: fixed; diff --git a/app/templates/application.hbs b/app/templates/application.hbs index 51cd191..28f30f7 100644 --- a/app/templates/application.hbs +++ b/app/templates/application.hbs @@ -3,6 +3,10 @@