Skip to content

Commit

Permalink
#3367: Add custom fields to Location (client side)
Browse files Browse the repository at this point in the history
  • Loading branch information
cemalettin-work committed Dec 23, 2020
1 parent aca16f5 commit 53b8793
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 11 deletions.
78 changes: 78 additions & 0 deletions anet-dictionary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
14 changes: 13 additions & 1 deletion client/src/models/Location.js
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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({
Expand Down Expand Up @@ -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 &&
Expand Down
17 changes: 14 additions & 3 deletions client/src/pages/locations/Edit.js
Original file line number Diff line number Diff line change
@@ -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, {
Expand All @@ -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`
Expand Down Expand Up @@ -52,7 +56,8 @@ const GQL_GET_LOCATION = gql`
avatar(size: 32)
}
}
}
}
customFields
${GRAPHQL_NOTES_FIELDS}
}
}
Expand All @@ -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 (
<div>
Expand Down
27 changes: 24 additions & 3 deletions client/src/pages/locations/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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`
Expand Down Expand Up @@ -94,6 +99,7 @@ const LocationForm = ({ edit, title, initialValues }) => {
setFieldValue,
setValues,
values,
validateForm,
submitForm
}) => {
const marker = {
Expand Down Expand Up @@ -189,7 +195,19 @@ const LocationForm = ({ edit, title, initialValues }) => {
setFieldValue={setFieldValue}
approversFilters={approversFilters}
/>

{Settings.fields.location.customFields && (
<Fieldset title="Location information" id="custom-fields">
<CustomFieldsContainer
fieldsConfig={Settings.fields.location.customFields}
formikProps={{
setFieldTouched,
setFieldValue,
values,
validateForm
}}
/>
</Fieldset>
)}
<div className="submit-buttons">
<div>
<Button onClick={onCancel}>Cancel</Button>
Expand Down Expand Up @@ -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
})
Expand Down
7 changes: 5 additions & 2 deletions client/src/pages/locations/New.js
Original file line number Diff line number Diff line change
@@ -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 }) => {
Expand All @@ -17,7 +19,8 @@ const LocationNew = ({ pageDispatchers }) => {
})

const location = new Location()

// mutates the object
initInvisibleFields(location, Settings.fields.location.customFields)
return <LocationForm initialValues={location} title="Create a new Location" />
}

Expand Down
19 changes: 18 additions & 1 deletion client/src/pages/locations/Show.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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`
Expand Down Expand Up @@ -64,6 +68,7 @@ const GQL_GET_LOCATION = gql`
}
}
}
customFields
${GRAPHQL_NOTES_FIELDS}
}
}
Expand All @@ -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
Expand Down Expand Up @@ -156,6 +165,14 @@ const LocationShow = ({ pageDispatchers }) => {
</Fieldset>

<Leaflet markers={[marker]} />
{Settings.fields.location.customFields && (
<Fieldset title="Location information" id="custom-fields">
<ReadonlyCustomFields
fieldsConfig={Settings.fields.location.customFields}
values={values}
/>
</Fieldset>
)}
</Form>

<Approvals relatedObject={location} />
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/anet-schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 53b8793

Please sign in to comment.