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. @@ -72,6 +74,7 @@ import Loading from '../loading.vue'; import modal from '../../mixins/modal'; import routes from '../../mixins/routes'; import validateData from '../../mixins/validate-data'; +import { loadAsyncComponent } from '../../util/async-components'; import { requestData } from '../../store/modules/request'; const popoverContentTemplate = ` @@ -85,8 +88,19 @@ const popoverContentTemplate = ` export default { name: 'FieldKeyList', - components: { DocLink, FieldKeyRow, FieldKeyNew, FieldKeyRevoke, Loading }, - mixins: [modal(), routes(), validateData()], + components: { + DocLink, + FieldKeyRow, + FieldKeyNew, + FieldKeyRevoke, + Loading, + ProjectSubmissionOptions: loadAsyncComponent('ProjectSubmissionOptions') + }, + mixins: [ + modal({ submissionOptions: 'ProjectSubmissionOptions' }), + routes(), + validateData() + ], props: { projectId: { type: String, @@ -95,29 +109,27 @@ export default { }, data() { return { + // The id of the highlighted app user highlighted: null, enabledPopoverLinks: new Set(), // The element whose popover is currently shown. popoverLink: null, + // Modals newFieldKey: { state: false }, - revoke: { - fieldKey: null, + submissionOptions: { state: false + }, + revoke: { + state: false, + fieldKey: null } }; }, computed: requestData(['fieldKeys']), - watch: { - fieldKeys() { - this.enabledPopoverLinks = new Set(); - this.revoke.fieldKey = null; - this.hidePopover(); - } - }, created() { - this.$emit('fetch-field-keys', false); + this.fetchData(false); }, mounted() { $('body').on('click.field-key-list', this.hidePopoverAfterClickOutside); @@ -127,6 +139,11 @@ export default { $('body').off('.field-key-list'); }, methods: { + fetchData(resend) { + this.$emit('fetch-field-keys', resend); + this.highlighted = null; + this.enabledPopoverLinks = new Set(); + }, hidePopover() { if (this.popoverLink == null) return; $(this.popoverLink).popover('hide'); @@ -178,17 +195,20 @@ export default { this.revoke.fieldKey = fieldKey; this.showModal('revoke'); }, + hideRevoke() { + this.hideModal('revoke'); + this.revoke.fieldKey = null; + }, afterCreate(fieldKey) { - this.$emit('fetch-field-keys'); + this.fetchData(true); this.hideModal('newFieldKey'); this.$alert().success(this.$t('alert.create', fieldKey)); this.highlighted = fieldKey.id; }, afterRevoke(fieldKey) { - this.$emit('fetch-field-keys'); - this.hideModal('revoke'); + this.fetchData(true); + this.hideRevoke(); this.$alert().success(this.$t('alert.revoke', fieldKey)); - this.highlighted = null; } } }; @@ -204,10 +224,6 @@ export default { width: $padding-left-table-data + $padding-right-table-data + $min-width-dropdown-menu; } - - td { - vertical-align: middle; - } } #field-key-list-popover-content { @@ -230,10 +246,17 @@ export default { "action": { "create": "Create App User" }, - "heading": { - "full": "App Users in this Project only will be able to download and use Forms within this Project. When you create a new App User, it will not have access to any Forms at first. To set the Forms each App User may access, use the {formAccess} tab. Multiple devices can use the same App User profile without problem.", - "formAccess": "Form Access" - }, + "heading": [ + { + // {collect} is a link whose text is "ODK Collect". + "full": "App Users are used to collect data from an application such as {collect}. They typically represent a shared role such as “Vaccinator” but may also represent individuals. App Users in this Project can only download and use Forms within this Project. When you create a new App User, it will not have access to any Forms at first. To set the Forms each App User may access, use the {formAccess} tab.", + "formAccess": "Form Access" + }, + { + "full": "App Users are most appropriate when data collectors need access to multiple Forms, are offline, or you have a complex Form. If you need respondents to self-report or have an online-only form, {clickHere} for other options.", + "clickHere": "click here" + } + ], "header": { "lastUsed": "Last Used", // Header for the table column that shows QR codes to configure data collection clients such as ODK Collect. diff --git a/src/components/field-key/new.vue b/src/components/field-key/new.vue index f7243a3e6..5907d3948 100644 --- a/src/components/field-key/new.vue +++ b/src/components/field-key/new.vue @@ -20,12 +20,12 @@ except according to the terms contained in the LICENSE file. @@ -48,7 +48,7 @@ except according to the terms contained in the LICENSE file. @@ -97,6 +97,7 @@ export default { created: null }; }, + // The modal assumes that this data will exist when the modal is shown. computed: requestData(['project']), watch: { state(state) { diff --git a/src/components/field-key/revoke.vue b/src/components/field-key/revoke.vue index fad3abdf4..4e9a9de92 100644 --- a/src/components/field-key/revoke.vue +++ b/src/components/field-key/revoke.vue @@ -24,11 +24,11 @@ except according to the terms contained in the LICENSE file.

{{ $t('introduction[2]') }}