Skip to content

Commit

Permalink
Merge pull request #119 from opendatakit/response-table-changes
Browse files Browse the repository at this point in the history
Response table changes
  • Loading branch information
matthew-white authored Aug 24, 2018
2 parents b92bdd4 + 81adc57 commit 54f8694
Show file tree
Hide file tree
Showing 14 changed files with 148 additions and 171 deletions.
34 changes: 13 additions & 21 deletions lib/components/form/submission-row.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,29 +118,21 @@ export default {
case 'dateTime':
return DateTime.fromISO(rawValue).toFormat('yyyy/MM/dd HH:mm:ss');

case 'geopoint': {
const localeCoordinates = new Array(rawValue.coordinates.length);
// Latitude and longitude
for (let i = 0; i < 2; i += 1) {
localeCoordinates[i] = parseFloat(rawValue.coordinates[i])
// 7 decimal places provide precision of 0.011m at the equator.
case 'geopoint':
return rawValue
.coordinates
.map((coordinate, i) => {
// Limiting the number of decimal places helps ensure that the
// formatted value fits within the column width.
.toLocaleString(undefined, {
minimumFractionDigits: 7,
maximumFractionDigits: 7
// formatted value fits within the column width. For longitude and
// latitude, 7 decimal places provide precision of 0.011m at the
// equator.
const digits = i < 2 ? 7 : 1;
return coordinate.toLocaleString(undefined, {
minimumFractionDigits: digits,
maximumFractionDigits: digits
});
}
// Altitude
if (rawValue.coordinates.length === 3) {
localeCoordinates[2] = parseFloat(rawValue.coordinates[2])
.toLocaleString(undefined, {
minimumFractionDigits: 1,
maximumFractionDigits: 1
});
}
return localeCoordinates.join(' ');
}
})
.join(' ');

default:
return rawValue;
Expand Down
1 change: 0 additions & 1 deletion lib/presenters/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export default class Form {
this._form = form;
}

get id() { return this._form.id; }
get xmlFormId() { return this._form.xmlFormId; }
get name() { return this._form.name; }
get version() { return this._form.version; }
Expand Down
19 changes: 2 additions & 17 deletions test/components/form/analyze.spec.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
/*
Copyright 2017 ODK Central Developers
See the NOTICE file at the top-level directory of this distribution and at
https://github.com/opendatakit/central-frontend/blob/master/NOTICE.
This file is part of ODK Central. It is subject to the license terms in
the LICENSE file found in the top-level directory of this distribution and at
https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central,
including this file, may be copied, modified, propagated, or distributed
except according to the terms contained in the LICENSE file.
*/
import FormAnalyze from '../../../lib/components/form/analyze.vue';
import FormSubmissions from '../../../lib/components/form/submissions.vue';
import testData from '../../data';
Expand All @@ -23,10 +12,6 @@ const createFormWithSubmission = () => {
return testData.extendedForms.last();
};
const submissionsPath = (form) => `/forms/${form.xmlFormId}/submissions`;
const submissionsOData = () => {
const submissions = testData.extendedSubmissions.sorted();
return { value: submissions.map(submission => submission._oData) };
};
const clickAnalyzeButton = (wrapper) =>
trigger.click(wrapper.first('#form-submissions-analyze-button'))
.then(() => wrapper);
Expand All @@ -47,7 +32,7 @@ describe('FormAnalyze', () => {
propsData: { form: createFormWithSubmission() }
})
.respondWithData(() => testData.extendedForms.last()._schema)
.respondWithData(submissionsOData)
.respondWithData(testData.submissionOData)
.afterResponse(component => {
component.first(FormAnalyze).getProp('state').should.be.false();
return component;
Expand All @@ -61,7 +46,7 @@ describe('FormAnalyze', () => {
mockRoute(submissionsPath(createFormWithSubmission()), { attachToDocument: true })
.respondWithData(() => testData.extendedForms.last())
.respondWithData(() => testData.extendedForms.last()._schema)
.respondWithData(submissionsOData)
.respondWithData(testData.submissionOData)
.afterResponse(clickAnalyzeButton)
.then(app =>
trigger.click(app.first('#form-analyze-odata-url')).then(() => app))
Expand Down
16 changes: 3 additions & 13 deletions test/components/form/new.spec.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
/*
Copyright 2017 ODK Central Developers
See the NOTICE file at the top-level directory of this distribution and at
https://github.com/opendatakit/central-frontend/blob/master/NOTICE.
This file is part of ODK Central. It is subject to the license terms in
the LICENSE file found in the top-level directory of this distribution and at
https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central,
including this file, may be copied, modified, propagated, or distributed
except according to the terms contained in the LICENSE file.
*/
import FormNew from '../../../lib/components/form/new.vue';
import testData from '../../data';
import { mockHttp, mockRoute } from '../../http';
Expand All @@ -17,6 +6,7 @@ import { mountAndMark } from '../../destroy';
import { trigger } from '../../util';

const XML_FILENAME = 'test.xml';
const XML = '<a><b/></a>';

const findModal = (wrapper) => wrapper.first(FormNew);
const openModal = (wrapper) => trigger
Expand All @@ -28,7 +18,7 @@ const createForm = (modal) => {
};
const dataTransfer = () => {
const dt = new DataTransfer();
const file = new File([testData.extendedForms.last().xml], XML_FILENAME);
const file = new File([XML], XML_FILENAME);
dt.items.add(file);
return dt;
};
Expand Down Expand Up @@ -116,7 +106,7 @@ describe('FormNew', () => {
.then(modal => {
modal.data().reading.should.be.false();
modal.data().filename.should.equal(XML_FILENAME);
modal.data().xml.should.equal(testData.extendedForms.last().xml);
modal.data().xml.should.equal(XML);
const button = modal.first('#form-new-create-button');
button.element.disabled.should.be.false();
}));
Expand Down
10 changes: 3 additions & 7 deletions test/components/form/submissions.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('FormSubmissions', () => {
return mockRouteThroughLogin(path)
.respondWithData(() => form)
.respondWithData(() => form._schema)
.respondWithData(() => [])
.respondWithData(testData.submissionOData)
.afterResponses(app => app.vm.$route.path.should.equal(path));
});
});
Expand All @@ -32,18 +32,14 @@ describe('FormSubmissions', () => {
beforeEach(mockLogin);

const form = () => testData.extendedForms.firstOrCreatePast();
const submissionOData = () => {
const submissions = testData.extendedSubmissions.sorted();
return { value: submissions.map(submission => submission._oData) };
};
const loadSubmissions = (...args) => {
testData.extendedSubmissions.createPast(...args);
return mockHttp()
.mount(FormSubmissions, {
propsData: { form: form() }
})
.respondWithData(() => form()._schema)
.respondWithData(submissionOData);
.respondWithData(testData.submissionOData);
};

describe('table data', () => {
Expand Down Expand Up @@ -329,7 +325,7 @@ describe('FormSubmissions', () => {
collection: testData.extendedSubmissions,
respondWithData: [
() => form()._schema,
submissionOData
testData.submissionOData
],
tableSelector: `#form-submissions-table${i}`
}));
Expand Down
6 changes: 4 additions & 2 deletions test/data/administrators.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { validateUniqueCombination } from './validate';

// eslint-disable-next-line import/prefer-default-export
export const administrators = dataStore({
factory: () => ({
factory: ({ inPast, id, lastCreatedAt }) => ({
id,
displayName: faker.name.findName(),
email: faker.internet.email(),
meta: null
meta: null,
...faker.date.timestamps(inPast, [lastCreatedAt])
}),
validate: [
validateUniqueCombination(['email'])
Expand Down
3 changes: 0 additions & 3 deletions test/data/backups.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import { MAXIMUM_TEST_DURATION } from '../util';
import { dataStore } from './data-store';

const store = dataStore({
id: false,
createdAt: false,
updatedAt: false,
factory: () => {
const recentDate = BackupList.methods.recentDate();
// The earliest time, for testing purposes, for backups to have been
Expand Down
67 changes: 20 additions & 47 deletions test/data/data-store.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
import faker from '../faker';
import { uniqueSequence } from '../../lib/util';

const DEFAULT_FACTORY_OPTIONS = {
id: true,
createdAt: true,
updatedAt: true,
validate: []
};

class Factory {
constructor(store, options) {
this._store = store;
this._options = { ...DEFAULT_FACTORY_OPTIONS, ...options };
this._options = { ...options };
if (this._options.validate == null) this._options.validate = [];
this.reset();
}

reset() {
if (this._options.id) this._uniqueId = uniqueSequence();
if (this._options.createdAt) this._lastCreatedAt = null;
this._uniqueId = uniqueSequence();
this._lastCreatedAt = null;
}

options() { return this._options; }
Expand All @@ -26,15 +20,15 @@ class Factory {
newObject() returns a new valid object for the store. It can be called in any
of the following ways:
newObject(past)
newObject(past, constraintOrConstraints)
newObject(past, factoryFunctionOptions)
newObject(inPast)
newObject(inPast, constraintOrConstraints)
newObject(inPast, factoryFunctionOptions)
with the following parameters:
- past. If true, the value of the new object's createdAt property will be in
the past. If false, the value will be set to the current time. `past` has
no effect if the Factory's options specify that new objects be created
- inPast. If true, the value of the new object's createdAt property will be
in the past. If false, the value will be set to the current time. `inPast`
has no effect if the Factory's options specify that new objects be created
without a createdAt property.
- constraintOrConstraints. Either a String or an Array of Strings, where
each String is the name of one of the constraints specified in the
Expand All @@ -60,25 +54,20 @@ class Factory {
are usually more performant than constraints. We may remove constraints at
some point and replace them with factory function options.
*/
newObject(past, constraintsOrOptions = undefined) {
newObject(inPast, constraintsOrOptions = undefined) {
const { constraints, factoryFunctionOptions } =
this._constraintsAndOptions(constraintsOrOptions);
const { factory } = this._options;
const id = this._options.id ? this._uniqueId() : null;
const id = this._uniqueId();
for (;;) {
// An object that contains the base properties of the new object: id,
// createdAt, and updatedAt.
const base = {};
if (this._options.id) base.id = id;
if (this._options.createdAt) base.createdAt = this._createdAt(past);
if (this._options.updatedAt)
base.updatedAt = this._updatedAt(past, base.createdAt);
const object = Object.assign(
factory({ ...factoryFunctionOptions, ...base }),
base
);
const object = factory({
...factoryFunctionOptions,
inPast,
id,
lastCreatedAt: this._lastCreatedAt
});
if (this._isValid(object, constraints)) {
if (this._options.createdAt) this._lastCreatedAt = object.createdAt;
this._lastCreatedAt = object.createdAt;
return object;
}
}
Expand All @@ -102,22 +91,6 @@ class Factory {
return { constraints, factoryFunctionOptions: {} };
}

_createdAt(past) {
if (!past) return new Date().toISOString();
const createdAt = this._lastCreatedAt == null
? faker.date.past()
: faker.date.pastSince(this._lastCreatedAt);
return createdAt.toISOString();
}

_updatedAt(past, createdAt) {
if (!past || faker.random.boolean()) return null;
const updatedAt = this._options.createdAt
? faker.date.pastSince(createdAt)
: faker.date.past();
return updatedAt.toISOString();
}

_isValid(object, constraints) {
const validators = constraints.length !== 0
? [...this._options.validate, ...constraints]
Expand Down Expand Up @@ -215,7 +188,7 @@ class Store extends Collection {
update(object, callback) {
const { createdAt } = object;
callback(object);
if (this._factory.options().updatedAt) {
if (Object.prototype.hasOwnProperty.call(object, 'updatedAt')) {
// eslint-disable-next-line no-param-reassign
object.updatedAt = new Date().toISOString();
}
Expand Down
37 changes: 22 additions & 15 deletions test/data/fieldKeys.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,30 @@ import R from 'ramda';
import faker from '../faker';
import { administrators } from './administrators';
import { dataStore, view } from './data-store';
import { validateDateOrder } from './validate';

export const extendedFieldKeys = dataStore({
factory: () => ({
displayName: faker.name.findName(),
token: faker.random.arrayElement([faker.app.token(), null]),
meta: null,
lastUsed: faker.random.arrayElement([faker.date.past().toISOString(), null]),
createdBy: R.pick(
['id', 'displayName', 'meta', 'createdAt', 'updatedAt'],
administrators.randomOrCreatePast()
)
}),
validate: [
validateDateOrder('createdBy.createdAt', 'createdAt'),
validateDateOrder('createdAt', 'lastUsed')
],
factory: ({ inPast, id, lastCreatedAt }) => {
const createdBy = administrators.randomOrCreatePast();
const { createdAt, updatedAt } = faker.date.timestamps(inPast, [
lastCreatedAt,
createdBy.createdAt
]);
return {
id,
displayName: faker.name.findName(),
token: faker.random.arrayElement([faker.app.token(), null]),
meta: null,
lastUsed: inPast && faker.random.boolean()
? faker.date.pastSince(createdAt).toISOString()
: null,
createdBy: R.pick(
['id', 'displayName', 'meta', 'createdAt', 'updatedAt'],
createdBy
),
createdAt,
updatedAt
};
},
constraints: {
withAccess: (fieldKey) => fieldKey.token != null,
withAccessRevoked: (fieldKey) => fieldKey.token == null
Expand Down
Loading

0 comments on commit 54f8694

Please sign in to comment.