diff --git a/anet-dictionary.yml b/anet-dictionary.yml index 62977ce6eb..945ebae7af 100644 --- a/anet-dictionary.yml +++ b/anet-dictionary.yml @@ -476,6 +476,84 @@ fields: location: format: LAT_LON + customFields: + multipleButtons: + type: enumset + label: Choose one or more of the options + helpText: Help text for choosing multiple values + choices: + opt1: + label: Option 1 + opt2: + label: Option 2 + opt3: + label: Option 3 + inputFieldName: + type: text + label: Text field + placeholder: Placeholder text for input field + helpText: Help text for text field + colourOptions: + type: enum + label: Choose one of the colours + helpText: Help text for choosing colours + choices: + GREEN: + label: Green + color: '#c2ffb3' + AMBER: + label: Amber + color: '#ffe396' + RED: + label: Red + color: '#ff8279' + textareaFieldName: + type: text + label: Textarea field + placeholder: Placeholder text for textarea field + helpText: Help text for textarea field + componentClass: textarea + style: + height: 200px + visibleWhen: $[?(@.colourOptions === 'GREEN')] + numberFieldName: + type: number + typeError: Number field must be a number + label: Number field + placeholder: Placeholder text for number field + helpText: Help text for number field + validations: + - type: integer + - type: min + params: [5] + - type: max + params: [100] + visibleWhen: $[?((@.colourOptions === 'GREEN')||(@.colourOptions === 'RED'))] + nlt: + type: date + label: Not later than date + helpText: Help text for date field + nlt_dt: + type: datetime + label: Not later than datetime + helpText: Help text for datetime field + arrayFieldName: + type: array_of_objects + label: Array of objects + helpText: Here you can add as many objects as needed + addButtonLabel: Add an object + objectLabel: Object + objectFields: + textF: + type: text + label: Object text + placeholder: Placeholder text for object text field + helpText: Help text for object text field + dateF: + type: date + label: Object date + helpText: Help text for object date field + visibleWhen: $[?(@.colourOptions === 'GREEN')] position: name: 'Position Name' diff --git a/client/src/components/advancedSelectWidget/MultiTypeAdvancedSelectComponent.js b/client/src/components/advancedSelectWidget/MultiTypeAdvancedSelectComponent.js index e2747e3cf1..6ce20ebec6 100644 --- a/client/src/components/advancedSelectWidget/MultiTypeAdvancedSelectComponent.js +++ b/client/src/components/advancedSelectWidget/MultiTypeAdvancedSelectComponent.js @@ -94,7 +94,7 @@ const widgetPropsLocation = { overlayColumns: ["Name"], filterDefs: entityFilters, queryParams: { status: Model.STATUS.ACTIVE }, - fields: Models.Location.autocompleteQuery, + fields: Models.Location.autocompleteQueryWithNotes, addon: LOCATIONS_ICON } diff --git a/client/src/models/Location.js b/client/src/models/Location.js index 47361adf1f..98bce1ee4c 100644 --- a/client/src/models/Location.js +++ b/client/src/models/Location.js @@ -1,4 +1,7 @@ -import Model from "components/Model" +import Model, { + createCustomFieldsSchema, + GRAPHQL_NOTES_FIELDS +} from "components/Model" import { convertLatLngToMGRS, convertMGRSToLatLng } from "geoUtils" import _isEmpty from "lodash/isEmpty" import LOCATIONS_ICON from "resources/locations.png" @@ -17,6 +20,11 @@ export default class Location extends Model { REPORT_APPROVAL: "REPORT_APPROVAL" } + // create yup schema for the customFields, based on the customFields config + static customFieldsSchema = createCustomFieldsSchema( + Settings.fields.location.customFields + ) + static yupSchema = yup .object() .shape({ @@ -118,10 +126,14 @@ export default class Location extends Model { .nullable() .default([]) }) + // not actually in the database, the database contains the JSON customFields + .concat(Location.customFieldsSchema) .concat(Model.yupSchema) static autocompleteQuery = "uuid, name" + static autocompleteQueryWithNotes = `${this.autocompleteQuery} ${GRAPHQL_NOTES_FIELDS}` + static hasCoordinates(location) { return ( location && diff --git a/client/src/pages/locations/Edit.js b/client/src/pages/locations/Edit.js index d65e4052bb..701c70a384 100644 --- a/client/src/pages/locations/Edit.js +++ b/client/src/pages/locations/Edit.js @@ -1,9 +1,11 @@ import { DEFAULT_SEARCH_PROPS, PAGE_PROPS_NO_NAV } from "actions" import API from "api" import { gql } from "apollo-boost" +import { initInvisibleFields } from "components/CustomFields" +import { DEFAULT_CUSTOM_FIELDS_PARENT } from "components/Model" import { - PageDispatchersPropType, mapPageDispatchersToProps, + PageDispatchersPropType, useBoilerplate } from "components/Page" import RelatedObjectNotes, { @@ -13,6 +15,8 @@ import { Location } from "models" import React from "react" import { connect } from "react-redux" import { useParams } from "react-router-dom" +import Settings from "settings" +import utils from "utils" import LocationForm from "./Form" const GQL_GET_LOCATION = gql` @@ -52,7 +56,8 @@ const GQL_GET_LOCATION = gql` avatar(size: 32) } } - } + } + customFields ${GRAPHQL_NOTES_FIELDS} } } @@ -75,8 +80,14 @@ const LocationEdit = ({ pageDispatchers }) => { if (done) { return result } - + if (data) { + data.location[DEFAULT_CUSTOM_FIELDS_PARENT] = utils.parseJsonSafe( + data.location.customFields + ) + } const location = new Location(data ? data.location : {}) + // mutates the object + initInvisibleFields(location, Settings.fields.location.customFields) return (
diff --git a/client/src/pages/locations/Form.js b/client/src/pages/locations/Form.js index 8eeada0f6c..568b2b1933 100644 --- a/client/src/pages/locations/Form.js +++ b/client/src/pages/locations/Form.js @@ -2,11 +2,15 @@ import API from "api" import { gql } from "apollo-boost" import AppContext from "components/AppContext" import ApprovalsDefinition from "components/approvals/ApprovalsDefinition" +import { + CustomFieldsContainer, + customFieldsJSONString +} from "components/CustomFields" import * as FieldHelper from "components/FieldHelper" import Fieldset from "components/Fieldset" import Leaflet from "components/Leaflet" import Messages from "components/Messages" -import Model from "components/Model" +import Model, { DEFAULT_CUSTOM_FIELDS_PARENT } from "components/Model" import NavigationWarning from "components/NavigationWarning" import { jumpToTop } from "components/Page" import { FastField, Form, Formik } from "formik" @@ -17,6 +21,7 @@ import PropTypes from "prop-types" import React, { useContext, useState } from "react" import { Button } from "react-bootstrap" import { useHistory } from "react-router-dom" +import Settings from "settings" import GeoLocation from "./GeoLocation" const GQL_CREATE_LOCATION = gql` @@ -94,6 +99,7 @@ const LocationForm = ({ edit, title, initialValues }) => { setFieldValue, setValues, values, + validateForm, submitForm }) => { const marker = { @@ -189,7 +195,19 @@ const LocationForm = ({ edit, title, initialValues }) => { setFieldValue={setFieldValue} approversFilters={approversFilters} /> - + {Settings.fields.location.customFields && ( +
+ +
+ )}
@@ -260,8 +278,11 @@ const LocationForm = ({ edit, title, initialValues }) => { const location = Object.without( new Location(values), "notes", - "displayedCoordinate" + "displayedCoordinate", + "customFields", // initial JSON from the db + DEFAULT_CUSTOM_FIELDS_PARENT ) + location.customFields = customFieldsJSONString(values) return API.mutation(edit ? GQL_UPDATE_LOCATION : GQL_CREATE_LOCATION, { location }) diff --git a/client/src/pages/locations/New.js b/client/src/pages/locations/New.js index 45adf8e392..784e860256 100644 --- a/client/src/pages/locations/New.js +++ b/client/src/pages/locations/New.js @@ -1,12 +1,14 @@ import { DEFAULT_SEARCH_PROPS, PAGE_PROPS_NO_NAV } from "actions" +import { initInvisibleFields } from "components/CustomFields" import { - PageDispatchersPropType, mapPageDispatchersToProps, + PageDispatchersPropType, useBoilerplate } from "components/Page" import { Location } from "models" import React from "react" import { connect } from "react-redux" +import Settings from "settings" import LocationForm from "./Form" const LocationNew = ({ pageDispatchers }) => { @@ -17,7 +19,8 @@ const LocationNew = ({ pageDispatchers }) => { }) const location = new Location() - + // mutates the object + initInvisibleFields(location, Settings.fields.location.customFields) return } diff --git a/client/src/pages/locations/Show.js b/client/src/pages/locations/Show.js index ed79a1edaa..5e03fbedd7 100644 --- a/client/src/pages/locations/Show.js +++ b/client/src/pages/locations/Show.js @@ -3,11 +3,13 @@ import API from "api" import { gql } from "apollo-boost" import AppContext from "components/AppContext" import Approvals from "components/approvals/Approvals" +import { ReadonlyCustomFields } from "components/CustomFields" import * as FieldHelper from "components/FieldHelper" import Fieldset from "components/Fieldset" import Leaflet from "components/Leaflet" import LinkTo from "components/LinkTo" import Messages from "components/Messages" +import { DEFAULT_CUSTOM_FIELDS_PARENT } from "components/Model" import { mapPageDispatchersToProps, PageDispatchersPropType, @@ -24,6 +26,8 @@ import { Location } from "models" import React, { useContext } from "react" import { connect } from "react-redux" import { useLocation, useParams } from "react-router-dom" +import Settings from "settings" +import utils from "utils" import GeoLocation, { GEO_LOCATION_DISPLAY_TYPE } from "./GeoLocation" const GQL_GET_LOCATION = gql` @@ -64,6 +68,7 @@ const GQL_GET_LOCATION = gql` } } } + customFields ${GRAPHQL_NOTES_FIELDS} } } @@ -88,7 +93,11 @@ const LocationShow = ({ pageDispatchers }) => { if (done) { return result } - + if (data) { + data.location[DEFAULT_CUSTOM_FIELDS_PARENT] = utils.parseJsonSafe( + data.location.customFields + ) + } const location = new Location(data ? data.location : {}) const stateSuccess = routerLocation.state && routerLocation.state.success const stateError = routerLocation.state && routerLocation.state.error @@ -156,6 +165,14 @@ const LocationShow = ({ pageDispatchers }) => { + {Settings.fields.location.customFields && ( +
+ +
+ )} diff --git a/src/main/resources/anet-schema.yml b/src/main/resources/anet-schema.yml index 2f2bb71f29..63e69de990 100644 --- a/src/main/resources/anet-schema.yml +++ b/src/main/resources/anet-schema.yml @@ -523,6 +523,10 @@ properties: enum: [LAT_LON, MGRS] title: Coordinate format for location description: Used in the UI where a location's coordinate is shown. Defaults to LAT_LON. + customFields: + type: object + additionalProperties: + "$ref": "#/$defs/customField" position: type: object