From cc859a66e78b1db49d22062ae57734bccf957eb6 Mon Sep 17 00:00:00 2001 From: erinz Date: Fri, 15 Sep 2023 22:16:03 +0000 Subject: [PATCH 1/4] add custom fields filter --- .../sighting/useSightingSearchSchemas.js | 144 +++++++++++------- 1 file changed, 86 insertions(+), 58 deletions(-) diff --git a/src/models/sighting/useSightingSearchSchemas.js b/src/models/sighting/useSightingSearchSchemas.js index dab7046e..b01cfa5a 100644 --- a/src/models/sighting/useSightingSearchSchemas.js +++ b/src/models/sighting/useSightingSearchSchemas.js @@ -3,65 +3,92 @@ import OptionTermFilter from '../../components/filterFields/OptionTermFilter'; import PointDistanceFilter from '../../components/filterFields/PointDistanceFilter'; import SubstringFilter from '../../components/filterFields/SubstringFilter'; import DateRangeFilter from '../../components/filterFields/DateRangeFilter'; -import useSiteSettings from '../../models/site/useSiteSettings'; +import useSiteSettings from '../site/useSiteSettings'; import IntegerFilter from '../../components/filterFields/IntegerFilter'; import FloatFilter from '../../components/filterFields/FloatFilter'; import MultiSelectFilter from '../../components/filterFields/MultiSelectFilter'; import autogenNameFilter from '../../components/filterFields/autogenNameFilter'; export default function useSightingSearchSchemas() { - const { regionOptions, speciesOptions, pipelineStateOptions, stageOptions, booleanChoices } = useOptions(); + const { + regionOptions, + speciesOptions, + pipelineStateOptions, + stageOptions, + booleanChoices, + } = useOptions(); const { data: siteSettings } = useSiteSettings(); - const customSightingFields = siteSettings['site.custom.customFields.Sighting'].value.definitions || []; + const customSightingFields = + siteSettings['site.custom.customFields.Sighting'].value + .definitions || []; + console.log('custom sightings fields', customSightingFields); + const customEncounterFields = + siteSettings['site.custom.customFields.Encounter'].value + .definitions || []; let customFilter; - const excludedFieldTypes = ['individual', 'feetmeters']; - const customFields = customSightingFields.filter(data => - !excludedFieldTypes.includes(data.schema.displayType)) - .map(data => { - switch (data.schema.displayType) { - case "select": - customFilter = OptionTermFilter; - break; - case "string": - customFilter = SubstringFilter; - break; - case "integer": - customFilter = IntegerFilter; - break; - case "float": - customFilter = FloatFilter; - break; - case "multiselect": - customFilter = MultiSelectFilter; - break; - case "daterange": - customFilter = DateRangeFilter; - break; - case "boolean": - customFilter = OptionTermFilter; - break; - case "latlong": - customFilter = PointDistanceFilter; - break; - case "longstring": - customFilter = SubstringFilter; - break; - default: - customFilter = SubstringFilter; - break; - } - return { - id: data.name, - labelId: data.schema.label, - FilterComponent: customFilter, - filterComponentProps: { - filterId: data.name, - queryTerm: `customFields.${data.id}`, - queryTerms: [`customFields.${data.id}`], - choices: data.schema.choices? data.schema.choices : booleanChoices, - }, - }; - }) + const excludedFieldTypes = [ + 'individual', + 'feetmeters', + 'datepicker', + 'daterange', + ]; + + const filterFields = fields => + fields + .filter( + data => !excludedFieldTypes.includes(data.schema.displayType), + ) + .map(data => { + switch (data.schema.displayType) { + case 'select': + customFilter = OptionTermFilter; + break; + case 'string': + customFilter = SubstringFilter; + break; + case 'integer': + customFilter = IntegerFilter; + break; + case 'float': + customFilter = FloatFilter; + break; + case 'multiselect': + customFilter = MultiSelectFilter; + break; + case 'daterange': + customFilter = DateRangeFilter; + break; + case 'boolean': + customFilter = OptionTermFilter; + break; + case 'latlong': + customFilter = PointDistanceFilter; + break; + case 'longstring': + customFilter = SubstringFilter; + break; + default: + customFilter = SubstringFilter; + break; + } + return { + id: data.name, + labelId: data.schema.label, + FilterComponent: customFilter, + filterComponentProps: { + filterId: data.name, + queryTerm: `encounters.customField.${data.id}`, + queryTerms: [`encounters.customField.${data.id}`], + choices: data.schema.choices + ? data.schema.choices + : booleanChoices, + }, + }; + }); + + const sightingsField = filterFields(customSightingFields); + console.log(sightingsField); + const encountersField = filterFields(customEncounterFields); return [ { @@ -121,9 +148,9 @@ export default function useSightingSearchSchemas() { labelId: 'SPECIES', FilterComponent: OptionTermFilter, filterComponentProps: { - filterId: 'species', - queryTerm: 'taxonomy_guids', - choices: speciesOptions, + filterId: 'species', + queryTerm: 'taxonomy_guids', + choices: speciesOptions, }, }, { @@ -131,9 +158,9 @@ export default function useSightingSearchSchemas() { labelId: 'PIPELINE_STATE', FilterComponent: OptionTermFilter, filterComponentProps: { - filterId: 'pipelineState', - queryTerm: 'pipelineState', - choices: pipelineStateOptions, + filterId: 'pipelineState', + queryTerm: 'pipelineState', + choices: pipelineStateOptions, }, }, { @@ -182,6 +209,7 @@ export default function useSightingSearchSchemas() { queryTerm: 'location_geo_point', }, }, - ...customFields + ...sightingsField, + ...encountersField, ]; } From 00ac2a84a0014856b45f404b270b6f1c18d1f9d4 Mon Sep 17 00:00:00 2001 From: erinz Date: Tue, 19 Sep 2023 14:11:55 +0000 Subject: [PATCH 2/4] fix lint issue --- locale/en.json | 4 +- .../filterFields/OptionTermFilter.jsx | 10 +- src/components/filterFields/useBuildFilter.js | 81 ++++++++++++++ .../individual/useIndividualSearchSchemas.js | 97 +++++----------- .../sighting/useSightingSearchSchemas.js | 104 +++++++----------- 5 files changed, 153 insertions(+), 143 deletions(-) create mode 100644 src/components/filterFields/useBuildFilter.js diff --git a/locale/en.json b/locale/en.json index bd3aae8c..62200fb2 100644 --- a/locale/en.json +++ b/locale/en.json @@ -1260,5 +1260,7 @@ "CHANGE_LOG" : "Change Log", "TIME_CHANGE_OCCURRED" : "Time Change occurred", "MANAGE_REQUESTS" : "Manage Requests", - "NO_SEARCH_RESULT" : "Your search did not match any records." + "NO_SEARCH_RESULT" : "Your search did not match any records.", + "ENCOUNTER_SEX" : "Encounter sex", + "ENCOUNTER_SPECIES" : "Encounter species" } diff --git a/src/components/filterFields/OptionTermFilter.jsx b/src/components/filterFields/OptionTermFilter.jsx index 0f5d4d88..35aae281 100644 --- a/src/components/filterFields/OptionTermFilter.jsx +++ b/src/components/filterFields/OptionTermFilter.jsx @@ -33,8 +33,6 @@ const OptionTermFilter = function (props) { const [value, setValue] = useState(''); - const [values, setValues] = useState([]); - function getLabel(object) { if (object?.labelId) return intl.formatMessage({ id: object.labelId }); @@ -45,10 +43,8 @@ const OptionTermFilter = function (props) { !minimalLabels && (description || descriptionId); const translatedLabel = labelId - ? (intl.messages[labelId] - ? intl.formatMessage({ id: labelId }) - : labelId ) - : label; + ? intl.formatMessage({ id: labelId, defaultMessage: labelId }) + : label; const safeChoices = choices || []; @@ -87,7 +83,7 @@ const OptionTermFilter = function (props) { }} value={value} renderValue={currentValue => { - if(!currentValue) { + if (!currentValue) { return ''; } const selectedChoice = safeChoices.find( diff --git a/src/components/filterFields/useBuildFilter.js b/src/components/filterFields/useBuildFilter.js new file mode 100644 index 00000000..245e0fb2 --- /dev/null +++ b/src/components/filterFields/useBuildFilter.js @@ -0,0 +1,81 @@ +import OptionTermFilter from './OptionTermFilter'; +import SubstringFilter from './SubstringFilter'; +import IntegerFilter from './IntegerFilter'; +import FloatFilter from './FloatFilter'; +import MultiSelectFilter from './MultiSelectFilter'; +import DateRangeFilter from './DateRangeFilter'; +import PointDistanceFilter from './PointDistanceFilter'; +import useOptions from '../../hooks/useOptions'; + +const excludedFieldTypes = [ + 'individual', + 'feetmeters', + 'date', + 'daterange', +]; + +export default function useBuildFilter(fields, component) { + const { booleanChoices } = useOptions(); + let queryTerm; + let queryTerms; + if (component === 'sightings' || component === 'individuals') { + queryTerm = 'customFields'; + queryTerms = 'customFields'; + } else if (component === 'encounters') { + queryTerm = 'encounters.customFields'; + queryTerms = 'encounters.customFields'; + } + + return fields + .filter( + data => !excludedFieldTypes.includes(data.schema.displayType), + ) + .map(data => { + let customFilter; + switch (data.schema.displayType) { + case 'select': + customFilter = OptionTermFilter; + break; + case 'string': + customFilter = SubstringFilter; + break; + case 'integer': + customFilter = IntegerFilter; + break; + case 'float': + customFilter = FloatFilter; + break; + case 'multiselect': + customFilter = MultiSelectFilter; + break; + case 'daterange': + customFilter = DateRangeFilter; + break; + case 'boolean': + customFilter = OptionTermFilter; + break; + case 'latlong': + customFilter = PointDistanceFilter; + break; + case 'longstring': + customFilter = SubstringFilter; + break; + default: + customFilter = SubstringFilter; + break; + } + return { + id: data.name, + labelId: data.schema.label, + FilterComponent: customFilter, + filterComponentProps: { + filterId: data.name, + queryTerm: `${queryTerm}.${data.id}`, + queryTerms: [`${queryTerms}.${data.id}`], + choices: data.schema.choices + ? data.schema.choices + : booleanChoices, + }, + }; + }); +} diff --git a/src/models/individual/useIndividualSearchSchemas.js b/src/models/individual/useIndividualSearchSchemas.js index 283e4e08..fb632fc1 100644 --- a/src/models/individual/useIndividualSearchSchemas.js +++ b/src/models/individual/useIndividualSearchSchemas.js @@ -2,14 +2,12 @@ import useOptions from '../../hooks/useOptions'; import OptionTermFilter from '../../components/filterFields/OptionTermFilter'; import SubstringFilter from '../../components/filterFields/SubstringFilter'; import DateRangeFilter from '../../components/filterFields/DateRangeFilter'; -import PointDistanceFilter from '../../components/filterFields/PointDistanceFilter'; import IntegerFilter from '../../components/filterFields/IntegerFilter'; -import FloatFilter from '../../components/filterFields/FloatFilter'; -import MultiSelectFilter from '../../components/filterFields/MultiSelectFilter'; import autogenNameFilter from '../../components/filterFields/autogenNameFilter'; import sexOptions from '../../constants/sexOptions'; -import useSocialGroups from '../../models/socialGroups/useSocialGroups'; -import useSiteSettings from '../../models/site/useSiteSettings'; +import useSocialGroups from '../socialGroups/useSocialGroups'; +import useSiteSettings from '../site/useSiteSettings'; +import useBuildFilter from '../../components/filterFields/useBuildFilter'; const labeledSexOptions = sexOptions.map(o => ({ labelId: o?.filterLabelId || o.labelId, @@ -35,62 +33,25 @@ const hasAnnotationOptions = [ ]; export default function useIndividualSearchSchemas() { - const { speciesOptions, socialGroupRolesOptions, relationshipOptions, booleanChoices } = useOptions(); + const { + speciesOptions, + socialGroupRolesOptions, + relationshipOptions, + } = useOptions(); const { data: socialGroups } = useSocialGroups(); const { data: siteSettings } = useSiteSettings(); - const customIndividualFields = siteSettings['site.custom.customFields.Individual'].value.definitions || []; - const socialGroupOptions = socialGroups?.map(data => { - return { - label: data.name, - value: data.guid - } - }); - let filterComponent1 = null; - const customFields = customIndividualFields.map(data => { - switch (data.schema.displayType) { - case "select": - filterComponent1 = OptionTermFilter; - break; - case "string": - filterComponent1 = SubstringFilter; - break; - case "integer": - filterComponent1 = IntegerFilter; - break; - case "float": - filterComponent1 = FloatFilter; - break; - case "multiselect": - filterComponent1 = MultiSelectFilter; - break; - case "daterange": - filterComponent1 = DateRangeFilter; - break; - case "boolean": - filterComponent1 = OptionTermFilter; - break; - case "latlong": - filterComponent1 = PointDistanceFilter; - break; - case "longstring": - filterComponent1 = SubstringFilter; - break; - default: - filterComponent1 = SubstringFilter; - break; - } - return { - id: data.name, - labelId: data.schema.label, - FilterComponent: filterComponent1, - filterComponentProps: { - filterId: data.name, - queryTerm: `customFields.${data.id}`, - queryTerms: [`customFields.${data.id}`], - choices: data.schema.choices? data.schema.choices : booleanChoices, - }, - }; - }) + const customIndividualFields = + siteSettings['site.custom.customFields.Individual'].value + .definitions || []; + const socialGroupOptions = socialGroups?.map(data => ({ + label: data.name, + value: data.guid, + })); + + const customFields = useBuildFilter( + customIndividualFields, + 'individuals', + ); return [ { @@ -189,8 +150,8 @@ export default function useIndividualSearchSchemas() { filterComponentProps: { queryTerm: 'relationships.type_guid', filterId: 'relationship', - choices: relationshipOptions, - } + choices: relationshipOptions, + }, }, { id: 'relationshipRoles', @@ -205,25 +166,25 @@ export default function useIndividualSearchSchemas() { }, { id: 'socialGroups', - labelId: 'SOCIAL_GROUPS', + labelId: 'SOCIAL_GROUPS', FilterComponent: OptionTermFilter, filterComponentProps: { queryTerm: 'social_groups.guid', filterId: 'socialGroups', - choices: socialGroupOptions + choices: socialGroupOptions, }, }, { id: 'socialGroupsRoles', - labelId: 'SOCIAL_GROUP_ROLES', + labelId: 'SOCIAL_GROUP_ROLES', FilterComponent: OptionTermFilter, filterComponentProps: { - customField: "social_group_roles", + customField: 'social_group_roles', queryTerm: 'social_groups.role_guids', filterId: 'socialGroupsRoles', - choices: socialGroupRolesOptions + choices: socialGroupRolesOptions, }, }, - ...customFields + ...customFields, ]; -} \ No newline at end of file +} diff --git a/src/models/sighting/useSightingSearchSchemas.js b/src/models/sighting/useSightingSearchSchemas.js index b01cfa5a..a0a5be00 100644 --- a/src/models/sighting/useSightingSearchSchemas.js +++ b/src/models/sighting/useSightingSearchSchemas.js @@ -5,9 +5,9 @@ import SubstringFilter from '../../components/filterFields/SubstringFilter'; import DateRangeFilter from '../../components/filterFields/DateRangeFilter'; import useSiteSettings from '../site/useSiteSettings'; import IntegerFilter from '../../components/filterFields/IntegerFilter'; -import FloatFilter from '../../components/filterFields/FloatFilter'; -import MultiSelectFilter from '../../components/filterFields/MultiSelectFilter'; import autogenNameFilter from '../../components/filterFields/autogenNameFilter'; +import useBuildFilter from '../../components/filterFields/useBuildFilter'; +import sexOptions from '../../constants/sexOptions'; export default function useSightingSearchSchemas() { const { @@ -15,80 +15,29 @@ export default function useSightingSearchSchemas() { speciesOptions, pipelineStateOptions, stageOptions, - booleanChoices, } = useOptions(); + + const labeledSexOptions = sexOptions.map(o => ({ + labelId: o?.filterLabelId || o.labelId, + value: o.value, + })); + const { data: siteSettings } = useSiteSettings(); const customSightingFields = siteSettings['site.custom.customFields.Sighting'].value .definitions || []; - console.log('custom sightings fields', customSightingFields); const customEncounterFields = siteSettings['site.custom.customFields.Encounter'].value .definitions || []; - let customFilter; - const excludedFieldTypes = [ - 'individual', - 'feetmeters', - 'datepicker', - 'daterange', - ]; - - const filterFields = fields => - fields - .filter( - data => !excludedFieldTypes.includes(data.schema.displayType), - ) - .map(data => { - switch (data.schema.displayType) { - case 'select': - customFilter = OptionTermFilter; - break; - case 'string': - customFilter = SubstringFilter; - break; - case 'integer': - customFilter = IntegerFilter; - break; - case 'float': - customFilter = FloatFilter; - break; - case 'multiselect': - customFilter = MultiSelectFilter; - break; - case 'daterange': - customFilter = DateRangeFilter; - break; - case 'boolean': - customFilter = OptionTermFilter; - break; - case 'latlong': - customFilter = PointDistanceFilter; - break; - case 'longstring': - customFilter = SubstringFilter; - break; - default: - customFilter = SubstringFilter; - break; - } - return { - id: data.name, - labelId: data.schema.label, - FilterComponent: customFilter, - filterComponentProps: { - filterId: data.name, - queryTerm: `encounters.customField.${data.id}`, - queryTerms: [`encounters.customField.${data.id}`], - choices: data.schema.choices - ? data.schema.choices - : booleanChoices, - }, - }; - }); - const sightingsField = filterFields(customSightingFields); - console.log(sightingsField); - const encountersField = filterFields(customEncounterFields); + const sightingsField = useBuildFilter( + customSightingFields, + 'sightings', + ); + const encountersField = useBuildFilter( + customEncounterFields, + 'encounters', + ); return [ { @@ -209,6 +158,27 @@ export default function useSightingSearchSchemas() { queryTerm: 'location_geo_point', }, }, + { + id: 'enounterspecies', + labelId: 'ENCOUNTER_SPECIES', + FilterComponent: OptionTermFilter, + filterComponentProps: { + filterId: 'enounterspecies', + queryTerm: 'encounters.taxonomy_guid', + choices: speciesOptions, + }, + }, + { + id: 'encounterSex', + labelId: 'ENCOUNTER_SEX', + FilterComponent: OptionTermFilter, + filterComponentProps: { + queryTerm: 'encounters.sex', + filterId: 'encounterSex', + choices: labeledSexOptions, + }, + }, + ...sightingsField, ...encountersField, ]; From f8d2d424cecfd345d58b9463dc5a40aed85c5a26 Mon Sep 17 00:00:00 2001 From: erinz Date: Wed, 20 Sep 2023 15:37:51 +0000 Subject: [PATCH 3/4] fix a encounter issue --- .../ElasticsearchSightingsDisplay.jsx | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/components/dataDisplays/ElasticsearchSightingsDisplay.jsx b/src/components/dataDisplays/ElasticsearchSightingsDisplay.jsx index 5cd86472..3b70f2ed 100644 --- a/src/components/dataDisplays/ElasticsearchSightingsDisplay.jsx +++ b/src/components/dataDisplays/ElasticsearchSightingsDisplay.jsx @@ -14,23 +14,24 @@ export default function ElasticsearchSightingsDisplay({ ...rest }) { const title = `${dataCount || sightings.length} matching sightings`; + console.log('sightings', sightings); const tableData = sightings.map(sighting => { - const encounters = sighting?.encounters || []; - const photoCount = encounters.reduce((memo, e) => { - memo += e.images.length; - return memo; - }, 0); + // const encounters = sighting?.encounters || []; + // const photoCount = encounters.reduce((memo, e) => { + // memo += e.images.length; + // return memo; + // }, 0); - const individuals = encounters.reduce((memo, e) => { - const individual = get(e, 'individual.id', null); - return individual ? [...memo, individual] : null; - }, []); + // const individuals = encounters.reduce((memo, e) => { + // const individual = get(e, 'individual.id', null); + // return individual ? [...memo, individual] : null; + // }, []); return { ...sighting, - photoCount, - individuals, + // photoCount, + // individuals, }; }); From 03a8f944625c50461dde3ed18469f4aa00cb6653 Mon Sep 17 00:00:00 2001 From: erinz Date: Wed, 20 Sep 2023 16:14:38 +0000 Subject: [PATCH 4/4] remove log --- src/components/dataDisplays/ElasticsearchSightingsDisplay.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/dataDisplays/ElasticsearchSightingsDisplay.jsx b/src/components/dataDisplays/ElasticsearchSightingsDisplay.jsx index 3b70f2ed..98bea22e 100644 --- a/src/components/dataDisplays/ElasticsearchSightingsDisplay.jsx +++ b/src/components/dataDisplays/ElasticsearchSightingsDisplay.jsx @@ -14,8 +14,7 @@ export default function ElasticsearchSightingsDisplay({ ...rest }) { const title = `${dataCount || sightings.length} matching sightings`; - console.log('sightings', sightings); - + const tableData = sightings.map(sighting => { // const encounters = sighting?.encounters || []; // const photoCount = encounters.reduce((memo, e) => {