diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d67745680..4fbf4a74b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -83,7 +83,7 @@ Most components are named according to the combination of a resource and an acti
* `Row`. A row of a `*Table` component.
* `Show`. A component that shows a single resource of a particular type.
* `Home`. A parent component of related components, for example, `SystemHome`.
-* `New`. A modal used to create a new resource of a particular type.
+* `Create` (or `New`). A modal used to create a new resource of a particular type.
* `Edit`. A component used to update an existing resource of a particular type.
* `Delete`. A modal used to delete an existing resource of a particular type.
diff --git a/src/assets/scss/_mixins.scss b/src/assets/scss/_mixins.scss
new file mode 100644
index 000000000..7a0eafe7b
--- /dev/null
+++ b/src/assets/scss/_mixins.scss
@@ -0,0 +1,8 @@
+@import './variables';
+
+// A list that shows descriptive text
+@mixin text-list {
+ max-width: $max-width-p;
+
+ li { margin-bottom: 5px; }
+}
diff --git a/src/assets/scss/_variables.scss b/src/assets/scss/_variables.scss
index fb8597231..bff53bd9a 100644
--- a/src/assets/scss/_variables.scss
+++ b/src/assets/scss/_variables.scss
@@ -18,8 +18,12 @@ $color-page-background: #f7f7f7;
// Text
$color-text: #333;
$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
+// 15-17 words per line
$max-width-p: 600px;
+// Icons
+$margin-right-icon: 6px;
+
// Contextual colors
$color-success: #0d840f;
$color-success-light: #ddf1d5;
diff --git a/src/assets/scss/app.scss b/src/assets/scss/app.scss
index 55902b90a..31642a861 100644
--- a/src/assets/scss/app.scss
+++ b/src/assets/scss/app.scss
@@ -10,7 +10,7 @@ including this file, may be copied, modified, propagated, or distributed
except according to the terms contained in the LICENSE file.
*/
-@import './variables';
+@import './mixins';
html {
background-color: $color-accent-secondary;
@@ -31,10 +31,7 @@ h1, .h1 {
margin-bottom: 3px;
}
-p {
- // 15-17 words per line
- max-width: 600px;
-}
+p { max-width: $max-width-p; }
@@ -49,7 +46,7 @@ p {
vertical-align: -1px;
.btn > &:first-child, a > &:first-child {
- margin-right: 6px;
+ margin-right: $margin-right-icon;
+ .caret { margin-left: 0; }
}
@@ -338,13 +335,26 @@ a {
////////////////////////////////////////////////////////////////////////////////
// PAGE STRUCTURE
-.heading-with-button {
+/*
+Most pages render a PageHead and a PageBody. The PageBody will often contain one
+or more PageSection components. Some pages use .panel-simple, but this is an
+older pattern: try to use PageSection instead.
+
+The PageBody component may show a heading at the top. Right now we implement
+this using the page-body-heading class, but we may create a component if it
+becomes more complicated.
+*/
+
+// .heading-with-button is deprecated: use .page-body-heading instead.
+.page-body-heading, .heading-with-button {
margin-bottom: 25px;
- > button {
+ > .btn {
float: right;
margin-left: 20px;
}
+
+ ul { @include text-list; }
}
diff --git a/src/components/audit/filters.vue b/src/components/audit/filters.vue
index 310e9c6d6..9b2167808 100644
--- a/src/components/audit/filters.vue
+++ b/src/components/audit/filters.vue
@@ -40,10 +40,12 @@ export default {
-
{
"en": {
diff --git a/src/components/audit/row.vue b/src/components/audit/row.vue
index 36e86f699..98a5d7c79 100644
--- a/src/components/audit/row.vue
+++ b/src/components/audit/row.vue
@@ -12,7 +12,7 @@ except according to the terms contained in the LICENSE file.
-
+
{{ type[0] }}
{{ type[1] }}
@@ -25,37 +25,44 @@ except according to the terms contained in the LICENSE file.
-
- {{ target.title }}
-
-
-
-
-
{{ details }}
+
+
+ {{ target.title }}
+
+ {{ target.title }}
+
+
{{ details }}
diff --git a/src/components/audit/table.vue b/src/components/audit/table.vue
index 5a9d3edb9..57ea9d25b 100644
--- a/src/components/audit/table.vue
+++ b/src/components/audit/table.vue
@@ -42,10 +42,6 @@ export default {
#audit-table {
table-layout: fixed;
}
-
-#audit-table th.details {
- width: 33.33333333%;
-}
diff --git a/src/components/field-key/list.vue b/src/components/field-key/list.vue
index 90a4c71f6..9bd3cef35 100644
--- a/src/components/field-key/list.vue
+++ b/src/components/field-key/list.vue
@@ -16,19 +16,19 @@ except according to the terms contained in the LICENSE file.
class="btn btn-primary" @click="showModal('newFieldKey')">
{{ $t('action.create') }}…
-
@@ -76,10 +78,24 @@ export default {
};
+
+
{
"en": {
+ // This is the text for an action, for example, the text of a button.
"seeCode": "See code",
+ // This text is shown for an App User whose access has been revoked.
"accessRevoked": "Access revoked",
"action": {
"revokeAccess": "Revoke access"
diff --git a/src/components/form-draft/checklist.vue b/src/components/form-draft/checklist.vue
index 5b05a676b..2f4fafa2d 100644
--- a/src/components/form-draft/checklist.vue
+++ b/src/components/form-draft/checklist.vue
@@ -47,8 +47,8 @@ except according to the terms contained in the LICENSE file.
{{ $t('steps[3].title') }}
-
- {{ $t('steps[3].body[0].testQrCode') }}
+
+ {{ $t('steps[3].body[0].test') }}
@@ -155,8 +155,8 @@ export default {
"title": "Test the Form on your mobile device",
"body": [
{
- "full": "It’s a good idea to test the Form to be sure it (still) works the way you expect. Using the {testQrCode}, you can make a test Submission that won’t affect your real data.",
- "testQrCode": "test QR code"
+ "full": "You can {test} a Form to be sure it works the way you expect. Test Submissions are not included in your final data.",
+ "test": "test"
}
]
},
diff --git a/src/components/form-draft/testing.vue b/src/components/form-draft/testing.vue
index 080c12162..f2f0603d6 100644
--- a/src/components/form-draft/testing.vue
+++ b/src/components/form-draft/testing.vue
@@ -16,9 +16,7 @@ except according to the terms contained in the LICENSE file.
{{ $t('title') }}
-
+
{{ $t('action.createSubmission') }}
@@ -76,10 +74,7 @@ export default {
computed: {
// The component does not assume that this data will exist when the
// component is created.
- ...requestData(['project', { key: 'formDraft', getOption: true }]),
- dataExists() {
- return this.$store.getters.dataExists(['project', 'formDraft']);
- },
+ ...requestData([{ key: 'formDraft', getOption: true }]),
qrCodeHtml() {
const url = apiPaths.serverUrlForFormDraft(
this.formDraft.draftToken,
@@ -126,8 +121,8 @@ export default {
// This is a title shown above a section of the page.
"title": "Draft Testing",
"body": [
- "You can use the configuration code to the right to set up a mobile device to download this Draft. If you fill a blank of the Draft Form and upload it, the Submission will go only into this test table below. You can preview and download the test Submissions below.",
- "When you publish this Draft Form, these test Submissions will be permanently removed."
+ "You can use the configuration code to the right to set up a mobile device to download this Draft. You can also click the New button above to create a new Submission from your web browser.",
+ "Draft Submissions go into the test table below, where you can preview and download them. When you publish this Draft Form, its test Submissions will be permanently removed."
]
}
}
diff --git a/src/components/form/checklist.vue b/src/components/form/checklist.vue
index bc67a0dca..46be577d5 100644
--- a/src/components/form/checklist.vue
+++ b/src/components/form/checklist.vue
@@ -28,33 +28,9 @@ except according to the terms contained in the LICENSE file.
{{ $tcn('steps[1].body[0].any', form.submissions) }}
- {{ $t('steps[1].body[1]') }}
-
- {{ $t('steps[1].body[2].none[0]') }}
-
-
-
- {{ $t('steps[1].body[2].none[1].appUsersTab') }}
-
-
-
-
-
-
-
- {{ $tcn('steps[1].body[2].any[0].countOfAppUsers', formActors.length) }}
-
-
-
- {{ $t('steps[1].body[2].any[0].addMore') }}
-
-
-
-
-
+
- {{ $t('steps[1].body[3].clickHere') }}
+ {{ $t('steps[1].body[1].clickHere') }}
@@ -100,7 +76,7 @@ import { requestData } from '../../store/modules/request';
// The component does not assume that this data will exist when the component is
// created.
-const requestKeys = ['project', 'form', 'formActors'];
+const requestKeys = ['project', 'form'];
export default {
name: 'FormChecklist',
@@ -119,13 +95,16 @@ export default {
false,
this.form.state !== 'open'
];
+ },
+ currentStep() {
+ return this.stepCompletion.findIndex(complete => !complete);
}
},
methods: {
stepStage(step) {
- if (this.stepCompletion[step]) return 'complete';
- const current = this.stepCompletion.findIndex(isComplete => !isComplete);
- return step === current ? 'current' : 'later';
+ return this.stepCompletion[step]
+ ? 'complete'
+ : (step === this.currentStep ? 'current' : 'later');
}
}
};
@@ -150,31 +129,11 @@ export default {
"body": [
{
"none": "Nobody has submitted any data to this Form yet.",
- "any": "A total of {count} Submission has been sent to this server. | A total of {count} Submissions have been sent to this server."
- },
- "App Users will be able to see this Form on their mobile device to download and fill out.",
- {
- "none": [
- "You have not created any App Users for this Project yet, so nobody will be able to use this Form.",
- {
- "full": "You can create them on the {appUsersTab}.",
- "appUsersTab": "App Users tab of the Project page"
- }
- ],
- "any": [
- {
- "full": [
- "Right now, {countOfAppUsers} in this Project has access to this Form, but you can always {addMore}.",
- "Right now, {countOfAppUsers} in this Project have access to this Form, but you can always {addMore}."
- ],
- "countOfAppUsers": "{count} App User | {count} App Users",
- "addMore": "add more"
- }
- ]
+ "any": "A total of {count} Submission has been made. | A total of {count} Submissions have been made."
},
{
- "full": "For more information about this, {clickHere}.",
- "clickHere": "click here"
+ "full": "{clickHere} to learn about the different ways to submit data.",
+ "clickHere": "Click here"
}
]
},
diff --git a/src/components/form/head.vue b/src/components/form/head.vue
index 0b995ed65..d8446b61d 100644
--- a/src/components/form/head.vue
+++ b/src/components/form/head.vue
@@ -58,7 +58,13 @@ except according to the terms contained in the LICENSE file.
diff --git a/src/components/modal.vue b/src/components/modal.vue
index 42ec47a21..31695f638 100644
--- a/src/components/modal.vue
+++ b/src/components/modal.vue
@@ -162,7 +162,7 @@ export default {
diff --git a/src/components/page/section.vue b/src/components/page/section.vue
index 613e236a3..63dbde25e 100644
--- a/src/components/page/section.vue
+++ b/src/components/page/section.vue
@@ -51,7 +51,7 @@ export default {
color: $color-accent-primary;
font-weight: bold;
- + button {
+ + .btn {
margin-left: 6px;
}
}
diff --git a/src/components/project/form-access.vue b/src/components/project/form-access.vue
index bdc691dec..686772fac 100644
--- a/src/components/project/form-access.vue
+++ b/src/components/project/form-access.vue
@@ -255,7 +255,7 @@ export default {
{
"en": {
"heading": [
- "Here you can set Form States, which control whether Forms are available for download and open for submission. You can also separately control which App Users may see each Form at all."
+ "App Users can only see and fill the Forms that they are explicity given access to in the table below. Project Managers and Data Collectors can use a web browser to fill out any Form in the Project that is in the Open state."
],
"emptyTable": "There are no Forms to show.",
"alert": {
diff --git a/src/components/project/form-access/table.vue b/src/components/project/form-access/table.vue
index b0635aa42..368036ec3 100644
--- a/src/components/project/form-access/table.vue
+++ b/src/components/project/form-access/table.vue
@@ -17,7 +17,7 @@ except according to the terms contained in the LICENSE file.
{{ $t('header.form') }}
- {{ $t('header.state') }}
+ {{ $t('header.state') }}
@@ -127,13 +127,9 @@ export default {
&:nth-child(2) {
width: $state-width;
- .btn-link {
- padding: 0;
-
- .icon-question-circle {
- margin-right: 0;
- }
- }
+ > span:first-child { margin-right: 5px; }
+ .btn-link { padding: 0; }
+ .icon-question-circle { margin-right: 0; }
}
}
}
diff --git a/src/components/project/introduction.vue b/src/components/project/introduction.vue
index 303a09364..aafe39f3d 100644
--- a/src/components/project/introduction.vue
+++ b/src/components/project/introduction.vue
@@ -10,23 +10,11 @@ including this file, may be copied, modified, propagated, or distributed
except according to the terms contained in the LICENSE file.
-->
-
+
{{ $t('title') }}
{{ $t('moreInfo.helpArticle.helpArticle') }}
@@ -62,17 +50,9 @@ export default {
{
"en": {
// This is the title at the top of a pop-up.
- "title": "Introducing Projects",
+ "title": "What are Projects?",
"introduction": [
- {
- "full": "ODK Central Beta v0.4 introduced {projects}.",
- "projects": "Projects"
- },
- {
- "full": "Projects group {forms} and {appUsers} together to make them easier to organize and manage, both on this website and on your data collection device.",
- "forms": "Forms",
- "appUsers": "App Users"
- }
+ "Projects let you group related Forms and Users. Web Users can be given Roles that let them perform certain actions within the Project, including using a web browser to fill out Forms. App Users for the Project can only see Forms in the Project which they have access to."
]
}
}
diff --git a/src/components/project/list.vue b/src/components/project/list.vue
index 344c42e18..fd3108004 100644
--- a/src/components/project/list.vue
+++ b/src/components/project/list.vue
@@ -51,7 +51,7 @@ except according to the terms contained in the LICENSE file.
-
+
@@ -106,7 +106,7 @@ except according to the terms contained in the LICENSE file.
@@ -120,7 +120,7 @@ except according to the terms contained in the LICENSE file.
-
@@ -162,14 +162,22 @@ export default {
},
computed: {
...requestData(['currentUser', 'projects', 'users']),
- loadingRightNow() {
+ // We should probably move the "Right Now" section into its own component.
+ rightNowKeys() {
const keys = ['projects'];
if (this.currentUser.can('user.list')) keys.push('users');
- return this.$store.getters.initiallyLoading(keys);
+ return keys;
+ },
+ loadingRightNow() {
+ return this.$store.getters.initiallyLoading(this.rightNowKeys);
+ },
+ dataExistsForRightNow() {
+ return this.$store.getters.dataExists(this.rightNowKeys);
},
- showsRightNow() {
- if (this.projects == null) return false;
- return !(this.currentUser.can('user.list') && this.users == null);
+ rendersIntroduction() {
+ if (this.projects == null || this.projects.length !== 1) return false;
+ const project = this.projects[0];
+ return project.name === 'Default Project' && project.forms === 0;
}
},
created() {
diff --git a/src/components/project/overview.vue b/src/components/project/overview.vue
index 640cea32f..d157dc903 100644
--- a/src/components/project/overview.vue
+++ b/src/components/project/overview.vue
@@ -46,11 +46,7 @@ export default {
// component is created.
...requestData(['project']),
rendersTopRow() {
- if (this.project == null) return false;
- // The text of ProjectOverviewAbout implies that the user can form.create.
- if (!this.project.permits('form.create')) return false;
- // ProjectOverviewRightNow links to .../app-users.
- return this.canRoute(this.projectPath('app-users'));
+ return this.project != null && this.project.permits('project.update');
}
},
watch: {
diff --git a/src/components/project/overview/about.vue b/src/components/project/overview/about.vue
index f60e65a21..c8944dd70 100644
--- a/src/components/project/overview/about.vue
+++ b/src/components/project/overview/about.vue
@@ -15,8 +15,11 @@ except according to the terms contained in the LICENSE file.
{{ $t('title') }}
-
@@ -37,10 +40,12 @@ except according to the terms contained in the LICENSE file.
@@ -50,8 +55,10 @@ export default {
// This is a title shown above a section of the page.
"title": "About Projects",
"body": [
- "Any Forms you create in this Project will only be visible on data collection devices to App Users who are a part of this Project.",
- "Future releases of ODK Central will add more Project-centric features, including improvements to Form states and workflow, device state updates, Collect settings management, and more granular permissioning.",
+ {
+ "full": "Projects let you group related Forms and Users. Web Users can be given Roles that let them perform certain actions within this Project, including using a web browser to fill out Forms. App Users for this Project can only see Forms in this Project which they have {accessTo}.",
+ "accessTo": "access to"
+ },
{
"full": "If you have any feedback, please visit {forumThread}.",
"forumThread": "this forum thread"
diff --git a/src/components/project/row.vue b/src/components/project/row.vue
index 1d1c67dcd..24a7b2e8d 100644
--- a/src/components/project/row.vue
+++ b/src/components/project/row.vue
@@ -18,7 +18,7 @@ except according to the terms contained in the LICENSE file.
-
+
+
+
+
+
+
+
+{
+ "en": {
+ // This is the title at the top of a pop-up.
+ "title": "Submission Options",
+ "introduction": [
+ // This text is shown above a list of options for submitting data.
+ "There are several options for submitting data to ODK Central:",
+ {
+ // This text is shown in a list of options for submitting data.
+ // {collect} is a link whose text is "ODK Collect".
+ "full": "Create {appUsers} and use the {collect} Android application. This is most appropriate when data collectors need access to multiple Forms, are offline, or you have a complex Form.",
+ "appUsers": "App Users"
+ },
+ {
+ // This text is shown in a list of options for submitting data.
+ "full": "Create one or more {publicLinks} to share with respondents who will self-report.",
+ "publicLinks": "Public Access Links"
+ },
+ {
+ // This text is shown in a list of options for submitting data.
+ "full": "Create a {webUser} with the Role of {dataCollector} for each individual who will be collecting data. These Users will log into Central to fill out this Form in a web browser. Project Managers can also create Submissions from a web browser.",
+ "webUser": "Web User",
+ "dataCollector": "Data Collector"
+ }
+ ]
+ }
+}
+
diff --git a/src/components/project/user/list.vue b/src/components/project/user/list.vue
index 5771ecb0f..9c5bcc2e7 100644
--- a/src/components/project/user/list.vue
+++ b/src/components/project/user/list.vue
@@ -15,12 +15,32 @@ component that each user is assigned at most one role and that the only roles
are Project Manager, Project Viewer, and Data Collector. -->