From d4e7d84136ba07d88e1a52dca876c49ba41b426d Mon Sep 17 00:00:00 2001 From: Anissa Agahchen Date: Thu, 31 Mar 2022 17:39:59 -0700 Subject: [PATCH 01/66] wip --- app/src/features/surveys/CreateSurveyPage.tsx | 16 ++++ .../components/PurposeAndMethologyForm.tsx | 89 +++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 app/src/features/surveys/components/PurposeAndMethologyForm.tsx diff --git a/app/src/features/surveys/CreateSurveyPage.tsx b/app/src/features/surveys/CreateSurveyPage.tsx index 09346c992e..f9e5e98eec 100644 --- a/app/src/features/surveys/CreateSurveyPage.tsx +++ b/app/src/features/surveys/CreateSurveyPage.tsx @@ -37,6 +37,7 @@ import yup from 'utils/YupSchema'; import { DATE_FORMAT, DATE_LIMIT } from 'constants/dateTimeFormats'; import moment from 'moment'; import { getFormattedAmount, getFormattedDate, getFormattedDateRangeString } from 'utils/Utils'; +import PurposeAndMethologyForm from './components/PurposeAndMethologyForm'; const useStyles = makeStyles((theme: Theme) => ({ actionButton: { @@ -389,6 +390,21 @@ const CreateSurveyPage = () => { + { + return { value: item.id, label: item.name }; + }) || [] + } + /> + }> + + + { + return yup.object().shape({ + additional_details: yup.string(), + intended_outcome: yup + .string() + .max(3000, 'Cannot exceed 3000 characters') + .required('You must provide a purpose for the survey') + }); +}; + +export interface IGeneralInformationFormProps { + intended_outcomes: IAutocompleteFieldOption[]; +} + +/** + * Create survey - general information fields + * + * @return {*} + */ +const PurposeAndMethologyForm: React.FC = (props) => { + const formikProps = useFormikContext(); + + return ( +
+ + + + Intended Outcomes + + + {formikProps.touched.intended_outcomes_id && formikProps.errors.intended_outcomes_id} + + + + + + + +
+ ); +}; + +export default PurposeAndMethologyForm; From 9924e8eea94d136ec686226639d64b3ad084e031 Mon Sep 17 00:00:00 2001 From: Anissa Agahchen Date: Mon, 4 Apr 2022 10:56:40 -0700 Subject: [PATCH 02/66] create survey page has the new purpose and methodology form --- app/src/features/surveys/CreateSurveyPage.tsx | 33 ++++++ .../components/GeneralInformationForm.tsx | 39 +------ .../components/PurposeAndMethologyForm.tsx | 108 ++++++++++++++++-- 3 files changed, 135 insertions(+), 45 deletions(-) diff --git a/app/src/features/surveys/CreateSurveyPage.tsx b/app/src/features/surveys/CreateSurveyPage.tsx index f9e5e98eec..abebf2a323 100644 --- a/app/src/features/surveys/CreateSurveyPage.tsx +++ b/app/src/features/surveys/CreateSurveyPage.tsx @@ -93,6 +93,24 @@ const CreateSurveyPage = () => { const [surveyFundingSources, setSurveyFundingSources] = useState([]); const [formikRef] = useState(useRef>(null)); + const intended_outcomes = [ + { id: 1, name: 'intended outcome 1' }, + { id: 2, name: 'intended outcome 2' }, + { id: 3, name: 'intended outcome 3' } + ]; + + const ecological_seasons = [ + { id: 1, name: 'ecological season 1' }, + { id: 2, name: 'ecological season 2' }, + { id: 3, name: 'ecological season 3' } + ]; + + const vantage_codes = [ + { id: 1, name: 'vantage code 1' }, + { id: 2, name: 'vantage code 2' }, + { id: 3, name: 'vantage code 3' } + ]; + // Ability to bypass showing the 'Are you sure you want to cancel' dialog const [enableCancelCheck, setEnableCancelCheck] = useState(true); @@ -396,10 +414,25 @@ const CreateSurveyPage = () => { component={ { + return { value: item.id, label: item.name }; + }) || [] + } + common_survey_methodologies={ codes?.common_survey_methodologies?.map((item) => { return { value: item.id, label: item.name }; }) || [] } + ecological_seasons={ + ecological_seasons.map((item) => { + return { value: item.id, label: item.name }; + }) || [] + } + vantage_codes={ + vantage_codes.map((item) => { + return { value: item.id, label: item.name }; + }) || [] + } /> }>
diff --git a/app/src/features/surveys/components/GeneralInformationForm.tsx b/app/src/features/surveys/components/GeneralInformationForm.tsx index 6388e723d2..1660063aac 100644 --- a/app/src/features/surveys/components/GeneralInformationForm.tsx +++ b/app/src/features/surveys/components/GeneralInformationForm.tsx @@ -54,10 +54,6 @@ export const GeneralInformationInitialValues: IGeneralInformationForm = { export const GeneralInformationYupSchema = (customYupRules?: any) => { return yup.object().shape({ survey_name: yup.string().required('Required'), - survey_purpose: yup - .string() - .max(3000, 'Cannot exceed 3000 characters') - .required('You must provide a purpose for the survey'), focal_species: yup.array().min(1, 'You must specify a focal species').required('Required'), ancillary_species: yup.array().isUniqueFocalAncillarySpecies('Focal and Ancillary species must be unique'), biologist_first_name: yup.string().required('Required'), @@ -96,7 +92,6 @@ const GeneralInformationForm: React.FC = (props) = onClick={() => { formikProps.setFieldValue('permit_number', ''); formikProps.setFieldValue('permit_type', ''); - setShowAddPermitRow(true); }}> Add Permit @@ -116,13 +111,13 @@ const GeneralInformationForm: React.FC = (props) = }} /> - + {/* - + */} = (props) = )}` } /> + + Species = (props) = required={false} /> - - - Survey Methodology - - - {formikProps.touched.common_survey_methodology_id && formikProps.errors.common_survey_methodology_id} - - - diff --git a/app/src/features/surveys/components/PurposeAndMethologyForm.tsx b/app/src/features/surveys/components/PurposeAndMethologyForm.tsx index 9c2a053d3f..4eae1b5d2c 100644 --- a/app/src/features/surveys/components/PurposeAndMethologyForm.tsx +++ b/app/src/features/surveys/components/PurposeAndMethologyForm.tsx @@ -1,4 +1,5 @@ //import Box from '@material-ui/core/Box'; +import { Box, Typography } from '@material-ui/core'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; import Grid from '@material-ui/core/Grid'; @@ -8,6 +9,7 @@ import Select from '@material-ui/core/Select'; //import Typography from '@material-ui/core/Typography'; import { IAutocompleteFieldOption } from 'components/fields/AutocompleteField'; import CustomTextField from 'components/fields/CustomTextField'; +import MultiAutocompleteFieldVariableSize from 'components/fields/MultiAutocompleteFieldVariableSize'; //import { IMultiAutocompleteFieldOption } from 'components/fields/MultiAutocompleteField'; //import MultiAutocompleteFieldVariableSize from 'components/fields/MultiAutocompleteFieldVariableSize'; import { useFormikContext } from 'formik'; @@ -17,25 +19,42 @@ import yup from 'utils/YupSchema'; export interface IPurposeAndMethologyForm { intended_outcomes_id: number; additional_details: string; + common_survey_methodology_id: number; + ecological_season_id: number; + vantage_code_id: number; } export const PurposeAndMethodologyInitialValues: IPurposeAndMethologyForm = { intended_outcomes_id: ('' as unknown) as number, - additional_details: '' + additional_details: '', + common_survey_methodology_id: ('' as unknown) as number, + ecological_season_id: ('' as unknown) as number, + vantage_code_id: ('' as unknown) as number }; export const GeneralInformationYupSchema = (customYupRules?: any) => { return yup.object().shape({ additional_details: yup.string(), intended_outcome: yup + .string() + .max(3000, 'Cannot exceed 3000 characters') + .required('You must provide a purpose for the survey'), + ecological_season: yup + .string() + .max(3000, 'Cannot exceed 3000 characters') + .required('You must provide a purpose for the survey'), + vantage_code: yup .string() .max(3000, 'Cannot exceed 3000 characters') .required('You must provide a purpose for the survey') }); }; -export interface IGeneralInformationFormProps { +export interface IPurposeAndMethodologyFormProps { intended_outcomes: IAutocompleteFieldOption[]; + common_survey_methodologies: IAutocompleteFieldOption[]; + ecological_seasons: IAutocompleteFieldOption[]; + vantage_codes: IAutocompleteFieldOption[]; } /** @@ -43,13 +62,16 @@ export interface IGeneralInformationFormProps { * * @return {*} */ -const PurposeAndMethologyForm: React.FC = (props) => { +const PurposeAndMethologyForm: React.FC = (props) => { const formikProps = useFormikContext(); return (
+ + Purpose of Survey + Intended Outcomes + {props.common_survey_methodologies.map((item) => ( + + {item.label} + + ))} + + + {formikProps.touched.common_survey_methodology_id && formikProps.errors.common_survey_methodology_id} + + + + + + Ecological Season + + + {formikProps.touched.ecological_season_id && formikProps.errors.ecological_season_id} + + + + + + +
); From 7ba6eeb7fe0932c9ec99cb9e71bd80b7bdbf23cf Mon Sep 17 00:00:00 2001 From: cgarrettjones Date: Mon, 4 Apr 2022 16:20:05 -0700 Subject: [PATCH 03/66] - addition of "ecological season", "intended outcome" and "vantage" lookup tables - "common survey methodology" table name change to "field method" - "survey.objectives" attribute name change to "survey.additional_details" - seeding new lookup tables - re-seed "field method" table --- .../migrations/20220404093900_SIMS.1.1.0.ts | 302 ++++++++++++++++++ .../smoketest_release.1.0.0.sql} | 1 - .../smoke_tests/smoketest_release.1.1.0.sql | 239 ++++++++++++++ 3 files changed, 541 insertions(+), 1 deletion(-) create mode 100644 database/src/migrations/20220404093900_SIMS.1.1.0.ts rename database/src/migrations/{release.0.34/smoketest_release.sql => smoke_tests/smoketest_release.1.0.0.sql} (99%) create mode 100644 database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql diff --git a/database/src/migrations/20220404093900_SIMS.1.1.0.ts b/database/src/migrations/20220404093900_SIMS.1.1.0.ts new file mode 100644 index 0000000000..84c7f7c983 --- /dev/null +++ b/database/src/migrations/20220404093900_SIMS.1.1.0.ts @@ -0,0 +1,302 @@ +import { Knex } from 'knex'; + +/** + * Apply biohub release changes. + * + * @export + * @param {Knex} knex + * @return {*} {Promise} + */ +export async function up(knex: Knex): Promise { + await knex.raw(` +set search_path = biohub, public; + +CREATE TABLE ecological_season( + ecological_season_id integer GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), + name varchar(50) NOT NULL, + record_effective_date date NOT NULL, + description varchar(3000), + record_end_date date, + create_date timestamptz(6) DEFAULT now() NOT NULL, + create_user integer NOT NULL, + update_date timestamptz(6), + update_user integer, + revision_count integer DEFAULT 0 NOT NULL, + CONSTRAINT ecological_season_pk PRIMARY KEY (ecological_season_id) +) +; + +COMMENT ON COLUMN ecological_season.ecological_season_id IS 'System generated surrogate primary key identifier.' +; +COMMENT ON COLUMN ecological_season.name IS 'The name of the project role.' +; +COMMENT ON COLUMN ecological_season.record_effective_date IS 'Record level effective date.' +; +COMMENT ON COLUMN ecological_season.description IS 'The description of the project type.' +; +COMMENT ON COLUMN ecological_season.record_end_date IS 'Record level end date.' +; +COMMENT ON COLUMN ecological_season.create_date IS 'The datetime the record was created.' +; +COMMENT ON COLUMN ecological_season.create_user IS 'The id of the user who created the record as identified in the system user table.' +; +COMMENT ON COLUMN ecological_season.update_date IS 'The datetime the record was updated.' +; +COMMENT ON COLUMN ecological_season.update_user IS 'The id of the user who updated the record as identified in the system user table.' +; +COMMENT ON COLUMN ecological_season.revision_count IS 'Revision count used for concurrency control.' +; +COMMENT ON TABLE ecological_season IS 'Broad classification for the ecological season of a survey.' +; + +-- +-- TABLE: intended_outcome +-- + +CREATE TABLE intended_outcome( + intended_outcome_id integer GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), + name varchar(50) NOT NULL, + record_effective_date date NOT NULL, + description varchar(3000), + record_end_date date, + create_date timestamptz(6) DEFAULT now() NOT NULL, + create_user integer NOT NULL, + update_date timestamptz(6), + update_user integer, + revision_count integer DEFAULT 0 NOT NULL, + CONSTRAINT intended_outcome_pk PRIMARY KEY (intended_outcome_id) +) +; + +COMMENT ON COLUMN intended_outcome.intended_outcome_id IS 'System generated surrogate primary key identifier.' +; +COMMENT ON COLUMN intended_outcome.name IS 'The name of the project role.' +; +COMMENT ON COLUMN intended_outcome.record_effective_date IS 'Record level effective date.' +; +COMMENT ON COLUMN intended_outcome.description IS 'The description of the project type.' +; +COMMENT ON COLUMN intended_outcome.record_end_date IS 'Record level end date.' +; +COMMENT ON COLUMN intended_outcome.create_date IS 'The datetime the record was created.' +; +COMMENT ON COLUMN intended_outcome.create_user IS 'The id of the user who created the record as identified in the system user table.' +; +COMMENT ON COLUMN intended_outcome.update_date IS 'The datetime the record was updated.' +; +COMMENT ON COLUMN intended_outcome.update_user IS 'The id of the user who updated the record as identified in the system user table.' +; +COMMENT ON COLUMN intended_outcome.revision_count IS 'Revision count used for concurrency control.' +; +COMMENT ON TABLE intended_outcome IS 'Broad classification of intended outcomes of the survey work.' +; + +-- +-- TABLE: vantage +-- + +CREATE TABLE vantage( + vantage_id integer GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), + name varchar(50) NOT NULL, + record_effective_date date NOT NULL, + description varchar(250), + record_end_date date, + create_date timestamptz(6) DEFAULT now() NOT NULL, + create_user integer NOT NULL, + update_date timestamptz(6), + update_user integer, + revision_count integer DEFAULT 0 NOT NULL, + CONSTRAINT vantage_pk PRIMARY KEY (vantage_id) +) +; + +COMMENT ON COLUMN vantage.vantage_id IS 'System generated surrogate primary key identifier.' +; +COMMENT ON COLUMN vantage.name IS 'The name of the project role.' +; +COMMENT ON COLUMN vantage.record_effective_date IS 'Record level effective date.' +; +COMMENT ON COLUMN vantage.description IS 'The description of the project type.' +; +COMMENT ON COLUMN vantage.record_end_date IS 'Record level end date.' +; +COMMENT ON COLUMN vantage.create_date IS 'The datetime the record was created.' +; +COMMENT ON COLUMN vantage.create_user IS 'The id of the user who created the record as identified in the system user table.' +; +COMMENT ON COLUMN vantage.update_date IS 'The datetime the record was updated.' +; +COMMENT ON COLUMN vantage.update_user IS 'The id of the user who updated the record as identified in the system user table.' +; +COMMENT ON COLUMN vantage.revision_count IS 'Revision count used for concurrency control.' +; +COMMENT ON TABLE vantage IS 'Broad classification for the vantage code of the survey.' +; + +CREATE UNIQUE INDEX ecological_season_nuk1 ON ecological_season(name, (record_end_date is NULL)) where record_end_date is null +; + +CREATE UNIQUE INDEX vantage_nuk1 ON vantage(name, (record_end_date is NULL)) where record_end_date is null +; + +CREATE UNIQUE INDEX intended_outcome_nuk1 ON intended_outcome(name, (record_end_date is NULL)) where record_end_date is null +; + +alter table survey +add column ecological_season_id integer, +add column intended_outcome_id integer, +add column vantage_id integer +; + +COMMENT ON COLUMN survey.ecological_season_id IS 'System generated surrogate primary key identifier.' +; +COMMENT ON COLUMN survey.intended_outcome_id IS 'System generated surrogate primary key identifier.' +; +COMMENT ON COLUMN survey.vantage_id IS 'System generated surrogate primary key identifier.' +; + +ALTER TABLE survey ADD CONSTRAINT "Refecological_season212" + FOREIGN KEY (ecological_season_id) + REFERENCES ecological_season(ecological_season_id) +; + +ALTER TABLE survey ADD CONSTRAINT "Refvantage214" + FOREIGN KEY (vantage_id) + REFERENCES vantage(vantage_id) +; + +ALTER TABLE survey ADD CONSTRAINT "Refintended_outcome211" + FOREIGN KEY (intended_outcome_id) + REFERENCES intended_outcome(intended_outcome_id) +; + +CREATE INDEX "Ref222214" ON survey(vantage_id) +; + +CREATE INDEX "Ref223211" ON survey(intended_outcome_id) +; + +CREATE INDEX "Ref220212" ON survey(ecological_season_id) +; + +alter table common_survey_methodology +rename to field_method +; + +alter table field_method +rename column common_survey_methodology_id to field_method_id +; + +alter table survey +rename column common_survey_methodology_id to field_method_id +; + +ALTER TABLE survey drop CONSTRAINT "Refcommon_survey_methodology190"; + +ALTER TABLE survey ADD CONSTRAINT "Reffield_method190" FOREIGN KEY (field_method_id) REFERENCES field_method(field_method_id); +ALTER TABLE survey ADD CONSTRAINT "Refvantage190" FOREIGN KEY (vantage_id) REFERENCES vantage(vantage_id); +ALTER TABLE survey ADD CONSTRAINT "Refecological_season190" FOREIGN KEY (ecological_season_id) REFERENCES ecological_season(ecological_season_id); +ALTER TABLE survey ADD CONSTRAINT "Refintended_outcome190" FOREIGN KEY (intended_outcome_id) REFERENCES intended_outcome(intended_outcome_id); + +alter table survey +rename column objectives to additional_details +; + +alter table survey +alter column additional_details drop not null +; + +alter trigger audit_common_survey_methodology on field_method rename to audit_field_method; +alter trigger journal_common_survey_methodology on field_method rename to journal_field_method; + +create trigger journal_intended_outcome after +insert or delete or update on biohub.intended_outcome for each row execute function biohub.tr_journal_trigger(); + +create trigger journal_ecological_season after +insert or delete or update on biohub.ecological_season for each row execute function biohub.tr_journal_trigger(); + +create trigger journal_vantage after +insert or delete or update on biohub.vantage for each row execute function biohub.tr_journal_trigger(); + +create trigger audit_intended_outcome before +insert or delete or update on biohub.intended_outcome for each row execute function biohub.tr_audit_trigger(); + +create trigger audit_ecological_season before +insert or delete or update on biohub.ecological_season for each row execute function biohub.tr_audit_trigger(); + +create trigger audit_vantage before +insert or delete or update on biohub.vantage for each row execute function biohub.tr_audit_trigger(); + +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Habitat Assessment', 'To assess habitat for its value to wildlife and to record evidence of its usage by wildlife.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Reconnaissance', 'To provide information for planning another Survey or to informally determine species presence.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Recruitment', 'To count or obtain an index of the number of new individuals (e.g., young) that have been added to the population between 2 points in time. For example, a caribou recruitment Survey counts young animals after winter; the young are considered established and contributing to the population.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Composition', 'To count or obtain an index of the number of individuals in a population belonging to particular age or sex categories. E.g., bull:cow ratio for moose.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Community Composition', 'To determine the numbers or proportions of species in an ecological community or geographic area. E.g., relative ground-cover by plant species, relative density of birds of each species in a forest.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Count', 'To obtain a number that indicates the number of individuals in an area. A population count may be obtained by enumerating every individual in a population (e.g., by doing a census) or by sampling a portion of the population (e.g., stratified random block design) and then adjusting the observed number to estimate the population size.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Count & Recruitment', 'To obtain a number that indicates the number of individuals in an area (population count) AND to count or obtain an index of the number of new individuals (e.g., young) that have been added to the population between 2 points in time (recruitment).'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Count & Composition', 'To obtain a number that indicates the number of individuals in an area (population count) AND to count or obtain an index of the number of individuals in a population belonging to particular age or sex categories (composition).'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Index', 'To obtain a population index. For example, to obtain a relative abundance index by calculating the number of tracks detected per kilometre of transect, or number of detections per hour of surveying.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Mortality', 'To count or obtain an index of the number and conditions of dead individuals, and/or the causes of death.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Survival', 'To count or obtain an index of the number of individuals in a population that have survived a period between 2 points in time.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Specimen Collection', 'To collect sample specimens of a species or taxon.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Translocation', 'To move individuals from one location to another.'); +insert into intended_outcome(record_effective_date, name, description) values (now(), 'Distribution or Range Map', 'To determine the manner in which a species (or population or taxon) is spatially arranged, or to define the geographic limits of the species.'); + +update field_method set description = 'A sampling technique in which a population is divided into discrete units called strata based on similar attributes. The researcher selects a small sample size with similar characteristics to represent a population group under study.' +where name = 'Stratified Random Block'; + +update field_method set record_end_date = now() +where name in ('Composition', 'Recruitment'); + +insert into field_method(record_effective_date, name, description) values (now(), 'Total Count', 'They are intended to enumerate all animals using 100% flight coverage of the study area. Alpine areas are usually small, and thus the technique is practical for surveying mountain sheep and goats, and sometimes caribou.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Encounter Transects', 'The recommended protocol for conducting herd composition surveys are encounter transects. Occasionally, however, sample blocks may be selected. The purpose of these surveys is to provide information on population composition and recruitment. Encounter transects can be flown by either fixed-wing aircraft or helicopter, and all visible animals are counted and classified. Encounter transects may follow predetermined straight lines, contours, or drainages. When classification is conducted, it will normally be necessary to deviate from the transect line to ensure accurate classification of the animals. Following the classification, the pilot should be instructed to resume the transect line. Ground transects are often secondary roads or trails.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Fixed-width Transects', 'When using fixed-width transects only animals within a defined survey area (strip) are counted. Fixed-widths can be defined by marks on the airplane struts, or by placing a board across the helicopter skids and calibrating that with a mark on the bubble window.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Wildlife Camera', 'To use a camera to record individuals or species in the absence of an observer.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Track Count', 'To count the number of tracks of a species or group of species.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Spotlight Count', 'To use a spotlight to see and identify or count the number of individuals.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Classification Transects/Blocks', 'The recommended protocol for conducting herd composition surveys are encounter transects. Occasionally, however, sample blocks may be selected. The purpose of these surveys is to provide information on population composition and recruitment.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Pellet/Scat Count', 'To count the number of pellet and/or scat groups of a species or group of species.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Call Playback', 'To play prerecorded calls of species and listen for responses.'); +insert into field_method(record_effective_date, name, description) values (now(), 'DNA - Individual', 'To obtain DNA samples from individuals.'); +insert into field_method(record_effective_date, name, description) values (now(), 'DNA - Environmental', 'To obtain environmental DNA.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture', 'To mark and subsequently resight or recapture individuals.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture - Wildlife Camera', 'To mark and subsequently resight or recapture individuals by use of a camera to record individuals or species in the absence of an observer.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture - Spotlight Count', 'To mark and subsequently resight or recapture individuals by use of a spotlight to see and identify or count the number of individuals.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture - DNA - Individual', 'To mark and subsequently resight or recapture individuals by obtaining DNA samples from individuals.'); +insert into field_method(record_effective_date, name, description) values (now(), 'Described in Comments', 'The field method is described in the comments field of the Survey. Note: Describing the data in comments rather than using a predefined code may reduce the clarity and accessibility of data.'); + +insert into ecological_season(record_effective_date, name, description) values (now(), 'Spring', ''); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Summer', ''); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Fall', ''); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Winter', ''); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Early Spring', ''); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Growing', 'The season of growth for a species; often includes all or portions of Spring, Summer, and Fall.'); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Early Winter', ''); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Mid Winter', ''); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Late Winter', ''); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Rutting', 'The courtship and copulation period of mammals, typically large mammals.'); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Breeding', 'The term "breeding season" typically applies to species, such as birds and some insects and some rodents, in which courtship and/or copulation is followed (within hours, days, or weeks) by hatching or birthing of young. In contrast, large mammals do not have a "breeding season" because they tend to have long gestation periods in which the birthing period is far removed from courtship and copulation.'); +insert into ecological_season(record_effective_date, name, description) values (now(), 'Post Birthing/Calving', 'The period after a species within a Study Area has finished giving birth to young, and the young are still closely associated with their parent(s) . For large mammals this period may start weeks after birthing, and extend for several weeks.'); + +insert into vantage(record_effective_date, name) values (now(), 'Aerial'); +insert into vantage(record_effective_date, name) values (now(), 'Walking'); +insert into vantage(record_effective_date, name) values (now(), 'Vehicle'); +insert into vantage(record_effective_date, name) values (now(), 'Boat'); + +set search_path = biohub_dapi_v1; + +alter view common_survey_methodology +rename to field_method +; + +create or replace view ecological_season as select * from biohub.ecological_season; +create or replace view vantage as select * from biohub.vantage; +create or replace view intended_outcome as select * from biohub.intended_outcome; +drop view survey; +create view survey as select * from biohub.survey; +`); +} + +export async function down(knex: Knex): Promise { + await knex.raw(``); +} diff --git a/database/src/migrations/release.0.34/smoketest_release.sql b/database/src/migrations/smoke_tests/smoketest_release.1.0.0.sql similarity index 99% rename from database/src/migrations/release.0.34/smoketest_release.sql rename to database/src/migrations/smoke_tests/smoketest_release.1.0.0.sql index 9fdeb3d45d..193c2ba196 100644 --- a/database/src/migrations/release.0.34/smoketest_release.sql +++ b/database/src/migrations/smoke_tests/smoketest_release.1.0.0.sql @@ -1,4 +1,3 @@ --- smoketest_release.sql -- run as db super user \c biohub set role postgres; diff --git a/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql b/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql new file mode 100644 index 0000000000..d6d7e4ccb7 --- /dev/null +++ b/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql @@ -0,0 +1,239 @@ +-- run as db super user +\c biohub +set role postgres; +set search_path=biohub; + +do $$ +declare + _count integer = 0; + _system_user system_user%rowtype; + _system_user_id system_user.system_user_id%type; +begin + select * into _system_user from system_user where user_identifier = 'myIDIR'; + if _system_user.system_user_id is not null then + delete from permit where system_user_id = _system_user.system_user_id; + delete from administrative_activity where reported_system_user_id = _system_user.system_user_id; + delete from administrative_activity where assigned_system_user_id = _system_user.system_user_id; + delete from system_user_role where system_user_id = _system_user.system_user_id; + delete from system_user where system_user_id = _system_user.system_user_id; + end if; + + insert into system_user (user_identity_source_id, user_identifier, record_effective_date) values ((select user_identity_source_id from user_identity_source where name = 'IDIR' and record_end_date is null), 'myIDIR', now()) returning system_user_id into _system_user_id; + insert into system_user_role (system_user_id, system_role_id) values (_system_user_id, (select system_role_id from system_role where name = 'System Administrator')); + + select count(1) into _count from system_user; + assert _count > 1, 'FAIL system_user'; + select count(1) into _count from audit_log; + assert _count > 1, 'FAIL audit_log'; + + -- drop security context for subsequent roles to instantiate + drop table biohub_context_temp; + + raise notice 'smoketest_release(1): PASS'; +end +$$; + +set role biohub_api; +set search_path to biohub_dapi_v1, biohub, public, topology; +do $$ +declare + _project_id project.project_id%type; + _survey_id survey.survey_id%type; + _count integer = 0; + _system_user_id system_user.system_user_id%type; + _study_species_id study_species.study_species_id%type; + _occurrence_submission_id occurrence_submission.occurrence_submission_id%type; + _submission_status_id submission_status.submission_status_id%type; + _survey_status_query text := 'select project_id, survey_id, survey_status from survey_status'; + _survey_status_rec survey_status%rowtype; + _geography project.geography%type; + _project_funding_source_id project_funding_source.project_funding_source_id%type; + _project_report_attachment_id project_report_attachment.project_report_attachment_id%type; + _survey_report_attachment_id survey_report_attachment.survey_report_attachment_id%type; +begin + -- set security context + select api_set_context('myIDIR', 'IDIR') into _system_user_id; + --select api_set_context('biohub_api', 'DATABASE') into _system_user_id; + + select st_GeomFromEWKT('SRID=4326;POLYGON((-123.920288 48.592142,-123.667603 48.645205,-123.539886 48.536204,-123.583832 48.46978,-123.728027 48.460674,-123.868103 48.467959,-123.940887 48.5262,-123.920288 48.592142), (-103.920288 38.592142,-103.667603 38.645205,-103.539886 38.536204,-103.583832 38.46978,-103.728027 38.460674,-103.868103 38.467959,-103.940887 38.5262,-103.920288 38.592142))') into _geography; + + insert into project (project_type_id + , name + , objectives + , start_date + , end_date + , coordinator_first_name + , coordinator_last_name + , coordinator_email_address + , coordinator_agency_name + , coordinator_public + , geography + ) values ((select project_type_id from project_type where name = 'Wildlife') + , 'project 10' + , 'my objectives' + , now() + , now()+interval '1 day' + , 'coordinator_first_name' + , 'coordinator_last_name' + , 'coordinator_email_address@nowhere.com' + , 'coordinator_agency_name' + , TRUE + , _geography + ) returning project_id into _project_id; + + insert into stakeholder_partnership (project_id, name) values (_project_id, 'test'); + insert into project_activity (project_id, activity_id) values (_project_id, (select activity_id from activity where name = 'Monitoring')); + insert into project_climate_initiative (project_id, climate_change_initiative_id) values (_project_id, (select climate_change_initiative_id from climate_change_initiative where name = 'Monitoring')); + insert into project_management_actions (project_id, management_action_type_id) values (_project_id, (select management_action_type_id from management_action_type where name = 'Recovery Action')); + insert into project_funding_source (project_id, investment_action_category_id, funding_amount, funding_start_date, funding_end_date, funding_source_project_id) values (_project_id, (select investment_action_category_id from investment_action_category where name = 'Action 1'), '$1,000.00', now(), now(), 'test') returning project_funding_source_id into _project_funding_source_id; + --insert into project_funding_source (project_id, investment_action_category_id, funding_amount, funding_start_date, funding_end_date) values (_project_id, 43, '$1,000.00', now(), now()); + insert into project_iucn_action_classification (project_id, iucn_conservation_action_level_3_subclassification_id) values (_project_id, (select iucn_conservation_action_level_3_subclassification_id from iucn_conservation_action_level_3_subclassification where name = 'Primary Education')); + insert into project_attachment (project_id, file_name, title, key, file_size, file_type) values (_project_id, 'test_filename.txt', 'test filename', 'projects/'||_project_id::text, 10000, 'video'); + insert into project_report_attachment (project_id, file_name, title, key, file_size, year, description) values (_project_id, 'test_filename.txt', 'test filename', 'projects/'||_project_id::text, 10000, '2021', 'example abstract') returning project_report_attachment_id into _project_report_attachment_id; + insert into project_report_author (project_report_attachment_id, first_name, last_name) values (_project_report_attachment_id, 'john', 'doe'); + insert into project_report_author (project_report_attachment_id, first_name, last_name) values (_project_report_attachment_id, 'bob', 'dole'); + insert into project_first_nation (project_id, first_nations_id) values (_project_id, (select first_nations_id from first_nations where name = 'Kitselas Nation')); + insert into permit (system_user_id, project_id, number, type, issue_date, end_date) values (_system_user_id, _project_id, '8377262', 'permit type', now(), now()+interval '1 day'); + + select count(1) into _count from stakeholder_partnership; + assert _count = 1, 'FAIL stakeholder_partnership'; + select count(1) into _count from project_activity; + assert _count = 1, 'FAIL project_activity'; + select count(1) into _count from project_climate_initiative; + assert _count = 1, 'FAIL project_climate_initiative'; + select count(1) into _count from project_management_actions; + assert _count = 1, 'FAIL project_management_actions'; + select count(1) into _count from project_funding_source; + assert _count = 1, 'FAIL project_funding_source'; + select count(1) into _count from project_iucn_action_classification; + assert _count = 1, 'FAIL project_iucn_action_classification'; + select count(1) into _count from project_attachment; + assert _count = 1, 'FAIL project_attachment'; + select count(1) into _count from project_attachment; + assert _count = 1, 'FAIL project_attachment'; + select count(1) into _count from project_report_attachment; + assert _count = 1, 'FAIL project_report_attachment'; + select count(1) into _count from project_report_author; + assert _count = 2, 'FAIL project_report_author'; + select count(1) into _count from project_first_nation; + assert _count = 1, 'FAIL project_first_nation'; + select count(1) into _count from permit; + assert _count = 1, 'FAIL permit'; + + -- surveys + insert into survey (project_id + , name + , additional_details + , location_name + , location_description + , start_date + , lead_first_name + , lead_last_name + , geography + , ecological_season_id + , intended_outcome_id + , vantage_id) + values (_project_id + , 'survey name' + , 'survey objectives' + , 'survey location name' + , 'survey location description' + , now() + , 'lead first' + , 'lead last' + , _geography + , (select ecological_season_id from ecological_season where name = 'Growing') + , (select intended_outcome_id from intended_outcome where name = 'Survival') + , (select vantage_id from vantage where name = 'Aerial')) returning survey_id into _survey_id; + + insert into survey_proprietor (survey_id, first_nations_id, proprietor_type_id, rationale,disa_required) + values (_survey_id, (select first_nations_id from first_nations where name = 'Squamish Nation'), (select proprietor_type_id from proprietor_type where name = 'First Nations Land'), 'proprietor rationale', true); + insert into survey_attachment (survey_id, file_name, title, key, file_size, file_type) values (_survey_id, 'test_filename.txt', 'test filename', 'projects/'||_project_id::text||'/surveys/'||_survey_id::text, 10000, 'video'); + insert into survey_report_attachment (survey_id, file_name, title, key, file_size, year, description) values (_survey_id, 'test_filename.txt', 'test filename', 'projects/'||_survey_id::text, 10000, '2021', 'example abstract') returning survey_report_attachment_id into _survey_report_attachment_id; + insert into survey_report_author (survey_report_attachment_id, first_name, last_name) values (_survey_report_attachment_id, 'john', 'doe'); + insert into survey_report_author (survey_report_attachment_id, first_name, last_name) values (_survey_report_attachment_id, 'bob', 'dole'); + insert into study_species (survey_id, wldtaxonomic_units_id, is_focal) values (_survey_id, (select wldtaxonomic_units_id from wldtaxonomic_units where CODE = 'AMARALB'), true); + insert into survey_funding_source (survey_id, project_funding_source_id) values (_survey_id, _project_funding_source_id); + + select count(1) into _count from survey; + assert _count = 1, 'FAIL survey'; + select count(1) into _count from survey_proprietor; + assert _count = 1, 'FAIL survey_proprietor'; + select count(1) into _count from survey_attachment where survey_id = _survey_id; + assert _count = 1, 'FAIL survey_attachment'; + select count(1) into _count from survey_report_attachment; + assert _count = 1, 'FAIL survey_report_attachment'; + select count(1) into _count from survey_report_author; + assert _count = 2, 'FAIL survey_report_author'; + select count(1) into _count from study_species; + assert _count = 1, 'FAIL study_species'; + select count(1) into _count from survey_funding_source; + assert _count = 1, 'FAIL survey_funding_source'; + + -- occurrence + -- occurrence submission 1 + insert into occurrence_submission (survey_id, source, event_timestamp) values (_survey_id, 'BIOHUB BATCH', now()-interval '1 day') returning occurrence_submission_id into _occurrence_submission_id; + select count(1) into _count from occurrence_submission; + assert _count = 1, 'FAIL occurrence_submission'; + insert into occurrence (occurrence_submission_id, taxonid, lifestage, eventdate, sex) values (_occurrence_submission_id, 'M-ALAL', 'Adult', now()-interval '10 day', 'male'); + select count(1) into _count from occurrence; + assert _count = 1, 'FAIL occurrence'; + insert into submission_status (occurrence_submission_id, submission_status_type_id, event_timestamp) values (_occurrence_submission_id, (select submission_status_type_id from submission_status_type where name = 'Submitted'), now()-interval '1 day') returning submission_status_id into _submission_status_id; + -- transpose comments on next three lines to test deletion of published surveys by system administrator + insert into submission_status (occurrence_submission_id, submission_status_type_id, event_timestamp) values (_occurrence_submission_id, (select submission_status_type_id from submission_status_type where name = 'Awaiting Curration'), now()-interval '1 day') returning submission_status_id into _submission_status_id; + insert into submission_status (occurrence_submission_id, submission_status_type_id, event_timestamp) values (_occurrence_submission_id, (select submission_status_type_id from submission_status_type where name = 'Published'), now()-interval '1 day') returning submission_status_id into _submission_status_id; + --insert into system_user_role (system_user_id, system_role_id) values (_system_user_id, (select system_role_id from system_role where name = 'System Administrator')); + + -- occurrence submission 2 + insert into occurrence_submission (survey_id, source, event_timestamp) values (_survey_id, 'BIOHUB BATCH', now()) returning occurrence_submission_id into _occurrence_submission_id; + select count(1) into _count from occurrence_submission; + assert _count = 2, 'FAIL occurrence_submission'; + insert into occurrence (occurrence_submission_id, taxonid, lifestage, eventdate, sex) values (_occurrence_submission_id, 'M-ALAL', 'Adult', now()-interval '5 day', 'female'); + select count(1) into _count from occurrence; + assert _count = 2, 'FAIL occurrence'; + insert into submission_status (occurrence_submission_id, submission_status_type_id, event_timestamp) values (_occurrence_submission_id, (select submission_status_type_id from submission_status_type where name = 'Submitted'), now()) returning submission_status_id into _submission_status_id; + insert into submission_status (occurrence_submission_id, submission_status_type_id, event_timestamp) values (_occurrence_submission_id, (select submission_status_type_id from submission_status_type where name = 'Rejected'), now()) returning submission_status_id into _submission_status_id; + insert into submission_message (submission_status_id, submission_message_type_id, event_timestamp, message) values (_submission_status_id, (select submission_message_type_id from submission_message_type where name = 'Missing Required Field'), now(), 'Some required field was not supplied.'); + select count(1) into _count from submission_status; + assert _count = 5, 'FAIL submission_status'; + select count(1) into _count from submission_message; + assert _count = 1, 'FAIL submission_message'; + +-- raise notice 'survey status (project_id, survey_id, survey_status):'; +-- for _survey_status_rec in execute _survey_status_query loop +-- raise notice 'survey status results are % % % %', _survey_status_rec.project_id, _survey_status_rec.survey_id, _survey_status_rec.occurrence_id, _survey_status_rec.survey_status; +-- end loop; + + -- test ancillary data + delete from webform_draft; + insert into webform_draft (system_user_id, name, data) values ((select system_user_id from system_user limit 1), 'my draft name', '{ "customer": "John Doe", "items": {"product": "Beer","qty": 6}}'); + select count(1) into _count from webform_draft; + assert _count = 1, 'FAIL webform_draft'; + + -- work ledger + delete from administrative_activity; + insert into administrative_activity (reported_system_user_id + , administrative_activity_type_id + , administrative_activity_status_type_id + , description + , data) + values (_system_user_id + , (select administrative_activity_type_id from administrative_activity_type where name = 'System Access') + , (select administrative_activity_status_type_id from administrative_activity_status_type where name = 'Pending') + , 'my activity' + , '{ "customer": "John Doe", "items": {"product": "Beer","qty": 6}}') + ; + select count(1) into _count from administrative_activity; + assert _count = 1, 'FAIL administrative_activity'; + + insert into permit (system_user_id, number, type, issue_date, end_date, coordinator_first_name, coordinator_last_name, coordinator_email_address, coordinator_agency_name) values (_system_user_id, '8377261', 'permit type', now(), now()+interval '1 day', 'first', 'last', 'nobody@nowhere.com', 'agency'); + + -- delete project + raise notice 'deleting data.'; + call api_delete_project(_project_id); + + raise notice 'smoketest_release(2): PASS'; +end +$$; + +delete from permit; From 5a24bfa89335ab9281a65ebd2979a16b9ec4b92f Mon Sep 17 00:00:00 2001 From: Anissa Agahchen Date: Tue, 5 Apr 2022 08:18:40 -0700 Subject: [PATCH 04/66] a bunch of front-end wiring up --- api/src/models/survey-create.ts | 4 +- api/src/openapi/schemas/survey.ts | 4 +- .../queries/survey/survey-create-queries.ts | 2 +- app/src/constants/i18n.ts | 8 + app/src/features/surveys/CreateSurveyPage.tsx | 24 +- .../components/GeneralInformationForm.tsx | 12 - ...Form.tsx => PurposeAndMethodologyForm.tsx} | 67 ++--- .../features/surveys/view/SurveyDetails.tsx | 10 + .../components/SurveyGeneralInformation.tsx | 21 +- .../SurveyPurposeAndMethodology.tsx | 278 ++++++++++++++++++ app/src/interfaces/useSurveyApi.interface.ts | 31 +- app/src/test-helpers/survey-helpers.ts | 9 +- 12 files changed, 382 insertions(+), 88 deletions(-) rename app/src/features/surveys/components/{PurposeAndMethologyForm.tsx => PurposeAndMethodologyForm.tsx} (70%) create mode 100644 app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx diff --git a/api/src/models/survey-create.ts b/api/src/models/survey-create.ts index 0b30d644ae..4ac65145e9 100644 --- a/api/src/models/survey-create.ts +++ b/api/src/models/survey-create.ts @@ -22,7 +22,7 @@ export class PostSurveyObject { end_date: string; survey_area_name: string; survey_data_proprietary: boolean; - survey_purpose: string; + intended_outcome: string; geometry: Feature[]; permit_number: string; permit_type: string; @@ -56,7 +56,7 @@ export class PostSurveyObject { this.funding_sources = (obj?.funding_sources?.length && obj.funding_sources) || []; this.survey_data_proprietary = obj?.survey_data_proprietary === 'true' || false; this.survey_name = obj?.survey_name || null; - this.survey_purpose = obj?.survey_purpose || null; + this.intended_outcome = obj?.intended_outcome || null; this.geometry = (obj?.geometry?.length && obj.geometry) || []; this.survey_proprietor = (obj && obj.survey_data_proprietary === 'true' && new PostSurveyProprietorData(obj)) || undefined; diff --git a/api/src/openapi/schemas/survey.ts b/api/src/openapi/schemas/survey.ts index b957162d9b..6b872e8fbd 100644 --- a/api/src/openapi/schemas/survey.ts +++ b/api/src/openapi/schemas/survey.ts @@ -10,7 +10,7 @@ export const surveyCreatePostRequestObject = { 'end_date', 'focal_species', 'ancillary_species', - 'survey_purpose', + 'intended_outcome', 'biologist_first_name', 'biologist_last_name', 'survey_area_name', @@ -42,7 +42,7 @@ export const surveyCreatePostRequestObject = { }, description: 'Selected ancillary species ids' }, - survey_purpose: { + intended_outcome: { type: 'string' }, biologist_first_name: { diff --git a/api/src/queries/survey/survey-create-queries.ts b/api/src/queries/survey/survey-create-queries.ts index e849747431..ef3a559497 100644 --- a/api/src/queries/survey/survey-create-queries.ts +++ b/api/src/queries/survey/survey-create-queries.ts @@ -40,7 +40,7 @@ export const postSurveySQL = (projectId: number, survey: PostSurveyObject): SQLS ) VALUES ( ${projectId}, ${survey.survey_name}, - ${survey.survey_purpose}, + ${survey.intended_outcome}, ${survey.start_date}, ${survey.end_date}, ${survey.biologist_first_name}, diff --git a/app/src/constants/i18n.ts b/app/src/constants/i18n.ts index 0ecb599366..e0d07fa411 100644 --- a/app/src/constants/i18n.ts +++ b/app/src/constants/i18n.ts @@ -91,6 +91,14 @@ export const EditSurveyProprietorI18N = { 'An error has occurred while attempting to edit your survey proprietor information, please try again. If the error persists, please contact your system administrator.' }; + +export const EditSurveyPurposeAndMethodologyI18N = { + editTitle: 'Edit Survey Purpose And Methodology', + editErrorTitle: 'Error Editing Survey Purpose And Methodology', + editErrorText: + 'An error has occurred while attempting to edit your survey purpose and methodology information, please try again. If the error persists, please contact your system administrator.' +}; + export const EditLocationBoundaryI18N = { editTitle: 'Edit Project Location', editErrorTitle: 'Error Editing Project Location', diff --git a/app/src/features/surveys/CreateSurveyPage.tsx b/app/src/features/surveys/CreateSurveyPage.tsx index abebf2a323..971a7d48aa 100644 --- a/app/src/features/surveys/CreateSurveyPage.tsx +++ b/app/src/features/surveys/CreateSurveyPage.tsx @@ -37,7 +37,7 @@ import yup from 'utils/YupSchema'; import { DATE_FORMAT, DATE_LIMIT } from 'constants/dateTimeFormats'; import moment from 'moment'; import { getFormattedAmount, getFormattedDate, getFormattedDateRangeString } from 'utils/Utils'; -import PurposeAndMethologyForm from './components/PurposeAndMethologyForm'; +import PurposeAndMethologyForm from './components/PurposeAndMethodologyForm'; const useStyles = makeStyles((theme: Theme) => ({ actionButton: { @@ -111,6 +111,14 @@ const CreateSurveyPage = () => { { id: 3, name: 'vantage code 3' } ]; + const field_methods = [ + { id: 1, name: 'method 1' }, + { id: 2, name: 'method 2' }, + { id: 3, name: 'method 3' } + ]; + + + // Ability to bypass showing the 'Are you sure you want to cancel' dialog const [enableCancelCheck, setEnableCancelCheck] = useState(true); @@ -377,11 +385,11 @@ const CreateSurveyPage = () => { return { value: item.id, label: item.name }; }) || [] } - common_survey_methodologies={ - codes?.common_survey_methodologies?.map((item) => { - return { value: item.id, label: item.name }; - }) || [] - } + // common_survey_methodologies={ + // codes?.common_survey_methodologies?.map((item) => { + // return { value: item.id, label: item.name }; + // }) || [] + // } permit_numbers={ surveyPermits?.map((item) => { return { value: item.number, label: `${item.number} - ${item.type}` }; @@ -418,8 +426,8 @@ const CreateSurveyPage = () => { return { value: item.id, label: item.name }; }) || [] } - common_survey_methodologies={ - codes?.common_survey_methodologies?.map((item) => { + field_methods={ + field_methods.map((item) => { return { value: item.id, label: item.name }; }) || [] } diff --git a/app/src/features/surveys/components/GeneralInformationForm.tsx b/app/src/features/surveys/components/GeneralInformationForm.tsx index 1660063aac..890627bf98 100644 --- a/app/src/features/surveys/components/GeneralInformationForm.tsx +++ b/app/src/features/surveys/components/GeneralInformationForm.tsx @@ -27,8 +27,6 @@ export interface IGeneralInformationForm { end_date: string; focal_species: number[]; ancillary_species: number[]; - survey_purpose: string; - common_survey_methodology_id: number; biologist_first_name: string; biologist_last_name: string; permit_number: string; @@ -42,8 +40,6 @@ export const GeneralInformationInitialValues: IGeneralInformationForm = { end_date: '', focal_species: [], ancillary_species: [], - survey_purpose: '', - common_survey_methodology_id: ('' as unknown) as number, biologist_first_name: '', biologist_last_name: '', permit_number: '', @@ -68,7 +64,6 @@ export interface IGeneralInformationFormProps { species: IMultiAutocompleteFieldOption[]; permit_numbers: IAutocompleteFieldOption[]; funding_sources: IMultiAutocompleteFieldOption[]; - common_survey_methodologies: IAutocompleteFieldOption[]; projectStartDate: string; projectEndDate: string; } @@ -111,13 +106,6 @@ const GeneralInformationForm: React.FC = (props) = }} /> - {/* - - */} { +export const PurposeAndMethodologyYupSchema = (customYupRules?: any) => { return yup.object().shape({ + field_method: yup.number().required('You must provide a field method'), additional_details: yup.string(), - intended_outcome: yup - .string() - .max(3000, 'Cannot exceed 3000 characters') - .required('You must provide a purpose for the survey'), - ecological_season: yup - .string() - .max(3000, 'Cannot exceed 3000 characters') - .required('You must provide a purpose for the survey'), - vantage_code: yup - .string() - .max(3000, 'Cannot exceed 3000 characters') - .required('You must provide a purpose for the survey') + intended_outcome: yup.number().required('You must provide intended outcomes for the survey'), + ecological_season: yup.number().required('You must provide an ecological season for the survey'), + vantage_code: yup.array().min(1, 'You must specify a vantage code').required('Required') }); }; export interface IPurposeAndMethodologyFormProps { intended_outcomes: IAutocompleteFieldOption[]; - common_survey_methodologies: IAutocompleteFieldOption[]; + field_methods: IAutocompleteFieldOption[]; ecological_seasons: IAutocompleteFieldOption[]; vantage_codes: IAutocompleteFieldOption[]; } @@ -63,7 +55,7 @@ export interface IPurposeAndMethodologyFormProps { * @return {*} */ const PurposeAndMethologyForm: React.FC = (props) => { - const formikProps = useFormikContext(); + const formikProps = useFormikContext(); return (
@@ -79,10 +71,10 @@ const PurposeAndMethologyForm: React.FC = (prop name="intended_outcomes_id" labelId="intended_outcomes_id-label" label="Intended Outcomes" - value={formikProps.values.intended_outcomes_id} + value={formikProps.values.intended_outcome} labelWidth={300} onChange={formikProps.handleChange} - error={formikProps.touched.intended_outcomes_id && Boolean(formikProps.errors.intended_outcomes_id)} + error={formikProps.touched.intended_outcome && Boolean(formikProps.errors.intended_outcome)} displayEmpty inputProps={{ 'aria-label': 'Intended Outcomes' }}> {props.intended_outcomes.map((item) => ( @@ -92,7 +84,7 @@ const PurposeAndMethologyForm: React.FC = (prop ))} - {formikProps.touched.intended_outcomes_id && formikProps.errors.intended_outcomes_id} + {formikProps.touched.intended_outcome && formikProps.errors.intended_outcome} @@ -115,24 +107,19 @@ const PurposeAndMethologyForm: React.FC = (prop name="field_methods_id" labelId="field_methods_id-label" label="Field Method" - value={formikProps.values.common_survey_methodology_id} + value={formikProps.values.field_method} labelWidth={300} onChange={formikProps.handleChange} - error={ - formikProps.touched.common_survey_methodology_id && - Boolean(formikProps.errors.common_survey_methodology_id) - } + error={formikProps.touched.field_method && Boolean(formikProps.errors.field_method)} displayEmpty inputProps={{ 'aria-label': 'Field Method' }}> - {props.common_survey_methodologies.map((item) => ( + {props.field_methods.map((item) => ( {item.label} ))} - - {formikProps.touched.common_survey_methodology_id && formikProps.errors.common_survey_methodology_id} - + {formikProps.touched.field_method && formikProps.errors.field_method} @@ -143,10 +130,10 @@ const PurposeAndMethologyForm: React.FC = (prop name="ecological_seasons_id" labelId="ecological_seasons_id-label" label="Ecological Season" - value={formikProps.values.ecological_season_id} + value={formikProps.values.ecological_season} labelWidth={300} onChange={formikProps.handleChange} - error={formikProps.touched.ecological_season_id && Boolean(formikProps.errors.ecological_season_id)} + error={formikProps.touched.ecological_season && Boolean(formikProps.errors.ecological_season)} displayEmpty inputProps={{ 'aria-label': 'Ecological Season' }}> {props.ecological_seasons.map((item) => ( @@ -156,7 +143,7 @@ const PurposeAndMethologyForm: React.FC = (prop ))} - {formikProps.touched.ecological_season_id && formikProps.errors.ecological_season_id} + {formikProps.touched.ecological_season && formikProps.errors.ecological_season} diff --git a/app/src/features/surveys/view/SurveyDetails.tsx b/app/src/features/surveys/view/SurveyDetails.tsx index d0f900b831..a8332a09a7 100644 --- a/app/src/features/surveys/view/SurveyDetails.tsx +++ b/app/src/features/surveys/view/SurveyDetails.tsx @@ -7,6 +7,7 @@ import { IGetAllCodeSetsResponse } from 'interfaces/useCodesApi.interface'; import { IGetProjectForViewResponse } from 'interfaces/useProjectApi.interface'; import { IGetSurveyForViewResponse } from 'interfaces/useSurveyApi.interface'; import React from 'react'; +import SurveyPurposeAndMethodology from './components/SurveyPurposeAndMethodology'; export interface ISurveyDetailsProps { surveyForViewData: IGetSurveyForViewResponse; @@ -35,6 +36,15 @@ const SurveyDetails: React.FC = (props) => { refresh={refresh} /> + + + + = (prop return { value: item.id, label: item.name }; }) || [] } - common_survey_methodologies={ - codes?.common_survey_methodologies?.map((item) => { - return { value: item.id, label: item.name }; - }) || [] - } + // common_survey_methodologies={ + // codes?.common_survey_methodologies?.map((item) => { + // return { value: item.id, label: item.name }; + // }) || [] + // } permit_numbers={ surveyPermits?.map((item) => { return { value: item.number, label: `${item.number} - ${item.type}` }; @@ -256,9 +256,6 @@ const SurveyGeneralInformation: React.FC = (prop toolbarProps={{ disableGutters: true }} /> - - {survey_details.survey_purpose} -
@@ -269,14 +266,6 @@ const SurveyGeneralInformation: React.FC = (prop {survey_details.survey_name} - - - Survey Methodology - - - {survey_details.common_survey_methodology || 'No Survey Methodology'} - - Survey Timeline diff --git a/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx b/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx new file mode 100644 index 0000000000..b1288b704d --- /dev/null +++ b/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx @@ -0,0 +1,278 @@ +import Box from '@material-ui/core/Box'; +import Divider from '@material-ui/core/Divider'; + +import { H3ButtonToolbar } from 'components/toolbar/ActionToolbars'; + +import Grid from '@material-ui/core/Grid'; +import Typography from '@material-ui/core/Typography'; +import { mdiPencilOutline } from '@mdi/js'; +import Icon from '@mdi/react'; +import EditDialog from 'components/dialog/EditDialog'; +import { ErrorDialog, IErrorDialogProps } from 'components/dialog/ErrorDialog'; +import { EditSurveyPurposeAndMethodologyI18N } from 'constants/i18n'; +import PurposeAndMethodologyForm, { + PurposeAndMethodologyInitialValues, + IPurposeAndMethodologyForm, + PurposeAndMethodologyYupSchema +} from 'features/surveys/components/PurposeAndMethodologyForm'; +import { APIError } from 'hooks/api/useAxios'; +import { useBiohubApi } from 'hooks/useBioHubApi'; +import { IGetAllCodeSetsResponse } from 'interfaces/useCodesApi.interface'; +import { IGetProjectForViewResponse } from 'interfaces/useProjectApi.interface'; +import { + IGetSurveyForUpdateResponsePurposeAndMethodology, + IGetSurveyForViewResponse, + UPDATE_GET_SURVEY_ENTITIES +} from 'interfaces/useSurveyApi.interface'; +import React, { useState } from 'react'; + +export interface ISurveyPurposeAndMethodologyDataProps { + surveyForViewData: IGetSurveyForViewResponse; + codes: IGetAllCodeSetsResponse; + projectForViewData: IGetProjectForViewResponse; + refresh: () => void; +} + +/** + * Proprietary data content for a survey. + * + * @return {*} + */ +const SurveyPurposeAndMethodologyData: React.FC = (props) => { + const biohubApi = useBiohubApi(); + + const { + projectForViewData, + surveyForViewData: { survey_details, survey_purpose_and_methodology }, + refresh + } = props; + + const [openEditDialog, setOpenEditDialog] = useState(false); + const [ + surveyDataForUpdate, + setSurveyDataForUpdate + ] = useState(null); + + const [purposeAndMethodologyFormData, setPurposeAndMethodologyFormData] = useState( + PurposeAndMethodologyInitialValues + ); + + const intended_outcomes = [ + { id: 1, name: 'intended outcome 1' }, + { id: 2, name: 'intended outcome 2' }, + { id: 3, name: 'intended outcome 3' } + ]; + + const ecological_seasons = [ + { id: 1, name: 'ecological season 1' }, + { id: 2, name: 'ecological season 2' }, + { id: 3, name: 'ecological season 3' } + ]; + + const vantage_codes = [ + { id: 1, name: 'vantage code 1' }, + { id: 2, name: 'vantage code 2' }, + { id: 3, name: 'vantage code 3' } + ]; + + const field_methods = [ + { id: 1, name: 'method 1' }, + { id: 2, name: 'method 2' }, + { id: 3, name: 'method 3' } + ]; + + const [errorDialogProps, setErrorDialogProps] = useState({ + dialogTitle: EditSurveyPurposeAndMethodologyI18N.editErrorTitle, + dialogText: EditSurveyPurposeAndMethodologyI18N.editErrorText, + open: false, + onClose: () => { + setErrorDialogProps({ ...errorDialogProps, open: false }); + }, + onOk: () => { + setErrorDialogProps({ ...errorDialogProps, open: false }); + } + }); + + const showErrorDialog = (textDialogProps?: Partial) => { + setErrorDialogProps({ ...errorDialogProps, ...textDialogProps, open: true }); + }; + + const handleDialogEditOpen = async () => { + if (!survey_purpose_and_methodology) { + setSurveyDataForUpdate(null); + setPurposeAndMethodologyFormData(PurposeAndMethodologyInitialValues); + setOpenEditDialog(true); + return; + } + + let surveyPurposeAndMethodologyResponseData; + + try { + const response = await biohubApi.survey.getSurveyForUpdate(projectForViewData.id, survey_details?.id, [ + UPDATE_GET_SURVEY_ENTITIES.survey_purpose_and_methodology + ]); + + if (!response) { + showErrorDialog({ open: true }); + return; + } + + surveyPurposeAndMethodologyResponseData = response?.survey_purpose_and_methodology || null; + } catch (error) { + const apiError = error as APIError; + showErrorDialog({ dialogText: apiError.message, open: true }); + return; + } + + setSurveyDataForUpdate(surveyPurposeAndMethodologyResponseData); + + setPurposeAndMethodologyFormData({ + intended_outcome: + surveyPurposeAndMethodologyResponseData?.intended_outcome || + PurposeAndMethodologyInitialValues.intended_outcome, + additional_details: + surveyPurposeAndMethodologyResponseData?.additional_details || + PurposeAndMethodologyInitialValues.additional_details, + field_method: + surveyPurposeAndMethodologyResponseData?.field_method || PurposeAndMethodologyInitialValues.field_method, + ecological_season: + surveyPurposeAndMethodologyResponseData?.ecological_season || + PurposeAndMethodologyInitialValues.ecological_season, + vantage_codes: + surveyPurposeAndMethodologyResponseData?.vantage_codes || PurposeAndMethodologyInitialValues.vantage_codes + }); + + setOpenEditDialog(true); + }; + + const handleDialogEditSave = async (values: IPurposeAndMethodologyForm) => { + const surveyData = { + survey_purpose_and_methodology: { + ...values, + id: surveyDataForUpdate?.id, + revision_count: surveyDataForUpdate?.revision_count + } + }; + + try { + await biohubApi.survey.updateSurvey(projectForViewData.id, survey_details.id, surveyData); + } catch (error) { + const apiError = error as APIError; + showErrorDialog({ dialogText: apiError.message, dialogErrorDetails: apiError.errors, open: true }); + return; + } finally { + setOpenEditDialog(false); + } + + refresh(); + }; + + return ( + <> + { + return { value: item.id, label: item.name }; + }) || [] + } + field_methods={ + field_methods.map((item) => { + return { value: item.id, label: item.name }; + }) || [] + } + ecological_seasons={ + ecological_seasons.map((item) => { + return { value: item.id, label: item.name }; + }) || [] + } + vantage_codes={ + vantage_codes.map((item) => { + return { value: item.id, label: item.name }; + }) || [] + } + /> + ), + initialValues: purposeAndMethodologyFormData, + validationSchema: PurposeAndMethodologyYupSchema + }} + onCancel={() => setOpenEditDialog(false)} + onSave={handleDialogEditSave} + /> + + + } + buttonOnClick={() => handleDialogEditOpen()} + toolbarProps={{ disableGutters: true }} + /> + +
+ {!survey_purpose_and_methodology && ( + + + + The data captured in this survey does not have the purpose and methodology section. + + + + )} + {survey_purpose_and_methodology && ( + + + + Proprietor Name + + + {survey_purpose_and_methodology.intended_outcome} + + + + + Data Category + + + {'put the additional comments in here'} + + + + + DISA Required + + + {survey_purpose_and_methodology.field_method} + + + + + Category Rationale + + + {survey_purpose_and_methodology.ecological_season} + + + + + + Category Rationale + + + {survey_purpose_and_methodology.vantage_codes} + + + + )} +
+
+ + ); +}; + +export default SurveyPurposeAndMethodologyData; diff --git a/app/src/interfaces/useSurveyApi.interface.ts b/app/src/interfaces/useSurveyApi.interface.ts index 2863ee98e2..5cd5f41931 100644 --- a/app/src/interfaces/useSurveyApi.interface.ts +++ b/app/src/interfaces/useSurveyApi.interface.ts @@ -24,7 +24,11 @@ export interface ICreateSurveyRequest { survey_area_name: string; survey_data_proprietary: string; survey_name: string; - survey_purpose: string; + intended_outcome: number; + additional_details: string; + field_method: number; + ecological_season: number; + vantage_codes: number[]; geometry: Feature[]; permit_number: string; } @@ -50,10 +54,8 @@ export interface ISurveyFundingSourceForView { export interface IGetSurveyForViewResponseDetails { id: number; survey_name: string; - survey_purpose: string; focal_species: string[]; ancillary_species: string[]; - common_survey_methodology: string; start_date: string; end_date: string; biologist_first_name: string; @@ -68,6 +70,14 @@ export interface IGetSurveyForViewResponseDetails { occurrence_submission_id: number | null; } +export interface IGetSurveyForViewResponsePurposeAndMethodology { + id: number; + intended_outcome: number; + field_method: number; + ecological_season: number; + vantage_codes: number[]; +} + export interface IGetSurveyForViewResponseProprietor { id: number; proprietary_data_category_name: string; @@ -80,10 +90,8 @@ export interface IGetSurveyForViewResponseProprietor { export interface IGetSurveyForUpdateResponseDetails { id: number; survey_name: string; - survey_purpose: string; focal_species: number[]; ancillary_species: number[]; - common_survey_methodology_id: number; start_date: string; end_date: string; biologist_first_name: string; @@ -96,6 +104,16 @@ export interface IGetSurveyForUpdateResponseDetails { funding_sources: number[]; } +export interface IGetSurveyForUpdateResponsePurposeAndMethodology { + id?: number; + intended_outcome: number; + additional_details: string; + field_method: number; + ecological_season: number; + vantage_codes: number[]; + revision_count?: number; +} + export interface IGetSurveyForUpdateResponseProprietor { id?: number; proprietary_data_category_name?: string; @@ -117,6 +135,7 @@ export interface IGetSurveyForUpdateResponseProprietor { */ export interface IGetSurveyForUpdateResponse { survey_details?: IGetSurveyForUpdateResponseDetails; + survey_purpose_and_methodology?: IGetSurveyForUpdateResponsePurposeAndMethodology | null; survey_proprietor?: IGetSurveyForUpdateResponseProprietor | null; } @@ -128,6 +147,7 @@ export interface IGetSurveyForUpdateResponse { */ export interface IGetSurveyForViewResponse { survey_details: IGetSurveyForViewResponseDetails; + survey_purpose_and_methodology: IGetSurveyForViewResponsePurposeAndMethodology; survey_proprietor: IGetSurveyForViewResponseProprietor; } @@ -158,6 +178,7 @@ export interface IGetSurveysListResponse { export enum UPDATE_GET_SURVEY_ENTITIES { survey_details = 'survey_details', + survey_purpose_and_methodology = 'survey_purpose_and_methodology', survey_proprietor = 'survey_proprietor' } diff --git a/app/src/test-helpers/survey-helpers.ts b/app/src/test-helpers/survey-helpers.ts index ee454c0846..d94628a32c 100644 --- a/app/src/test-helpers/survey-helpers.ts +++ b/app/src/test-helpers/survey-helpers.ts @@ -5,10 +5,8 @@ export const getSurveyForViewResponse: IGetSurveyForViewResponse = { id: 1, occurrence_submission_id: null, survey_name: 'survey name', - survey_purpose: 'survey purpose', focal_species: ['focal species 1'], ancillary_species: ['ancillary species 1'], - common_survey_methodology: 'method', start_date: '1998-10-10', end_date: '2021-02-26', biologist_first_name: 'first', @@ -49,6 +47,13 @@ export const getSurveyForViewResponse: IGetSurveyForViewResponse = { completion_status: 'Active', publish_date: (null as unknown) as string }, + survey_purpose_and_methodology:{ + id: 1, + intended_outcome: 1, + field_method: 1, + ecological_season: 1, + vantage_codes:[1,2] + }, survey_proprietor: { id: 23, proprietary_data_category_name: 'proprietor type', From c03dbe3faee692e5a803ceb241681d2b36767321 Mon Sep 17 00:00:00 2001 From: cgarrettjones Date: Tue, 5 Apr 2022 10:01:24 -0700 Subject: [PATCH 05/66] - adjusted field_method api view --- database/src/migrations/20220404093900_SIMS.1.1.0.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/database/src/migrations/20220404093900_SIMS.1.1.0.ts b/database/src/migrations/20220404093900_SIMS.1.1.0.ts index 84c7f7c983..3660352394 100644 --- a/database/src/migrations/20220404093900_SIMS.1.1.0.ts +++ b/database/src/migrations/20220404093900_SIMS.1.1.0.ts @@ -285,15 +285,13 @@ insert into vantage(record_effective_date, name) values (now(), 'Boat'); set search_path = biohub_dapi_v1; -alter view common_survey_methodology -rename to field_method -; - create or replace view ecological_season as select * from biohub.ecological_season; create or replace view vantage as select * from biohub.vantage; create or replace view intended_outcome as select * from biohub.intended_outcome; drop view survey; create view survey as select * from biohub.survey; +drop view common_survey_methodology; +create view field_method as select * from biohub.field_method; `); } From 7af6d478883642c8dd09abbed76cfe998cba3eb1 Mon Sep 17 00:00:00 2001 From: Anissa Agahchen Date: Tue, 5 Apr 2022 13:31:25 -0700 Subject: [PATCH 06/66] api changes --- api/src/paths/codes.ts | 44 ++++++++++++- api/src/queries/codes/code-queries.ts | 62 ++++++++++++++----- api/src/services/code-service.ts | 23 +++++-- app/src/features/surveys/CreateSurveyPage.tsx | 2 +- .../components/SurveyGeneralInformation.tsx | 2 +- app/src/interfaces/useCodesApi.interface.ts | 2 +- app/src/test-helpers/code-helpers.ts | 2 +- 7 files changed, 111 insertions(+), 26 deletions(-) diff --git a/api/src/paths/codes.ts b/api/src/paths/codes.ts index 3923b64876..c6ceb9ac61 100644 --- a/api/src/paths/codes.ts +++ b/api/src/paths/codes.ts @@ -270,7 +270,49 @@ GET.apiDoc = { } } }, - common_survey_methodologies: { + field_methods: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'number' + }, + name: { + type: 'string' + } + } + } + }, + ecological_seasons: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'number' + }, + name: { + type: 'string' + } + } + } + }, + intended_outcomes: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'number' + }, + name: { + type: 'string' + } + } + } + }, + vantage_codes: { type: 'array', items: { type: 'object', diff --git a/api/src/queries/codes/code-queries.ts b/api/src/queries/codes/code-queries.ts index 565d750691..3611ec37f7 100644 --- a/api/src/queries/codes/code-queries.ts +++ b/api/src/queries/codes/code-queries.ts @@ -6,7 +6,7 @@ import { SQL, SQLStatement } from 'sql-template-strings'; * @returns {SQLStatement} sql query object */ export const getManagementActionTypeSQL = (): SQLStatement => - SQL`SELECT management_action_type_id as id, name from management_action_type;`; + SQL`SELECT management_action_type_id as id, name from management_action_type where record_end_date is null;`; /** * SQL query to fetch first nation codes. @@ -14,7 +14,7 @@ export const getManagementActionTypeSQL = (): SQLStatement => * @returns {SQLStatement} sql query object */ export const getFirstNationsSQL = (): SQLStatement => - SQL`SELECT first_nations_id as id, name from first_nations ORDER BY name ASC;`; + SQL`SELECT first_nations_id as id, name from first_nations where record_end_date is null ORDER BY name ASC;`; /** * SQL query to fetch funding source codes. @@ -22,7 +22,7 @@ export const getFirstNationsSQL = (): SQLStatement => * @returns {SQLStatement} sql query object */ export const getFundingSourceSQL = (): SQLStatement => - SQL`SELECT funding_source_id as id, name from funding_source ORDER BY name ASC;`; + SQL`SELECT funding_source_id as id, name from funding_source where record_end_date is null ORDER BY name ASC;`; /** * SQL query to fetch proprietor type codes. @@ -30,29 +30,55 @@ export const getFundingSourceSQL = (): SQLStatement => * @returns {SQLStatement} sql query object */ export const getProprietorTypeSQL = (): SQLStatement => - SQL`SELECT proprietor_type_id as id, name, is_first_nation from proprietor_type;`; + SQL`SELECT proprietor_type_id as id, name, is_first_nation from proprietor_type where record_end_date is null;`; /** * SQL query to fetch activity codes. * * @returns {SQLStatement} sql query object */ -export const getActivitySQL = (): SQLStatement => SQL`SELECT activity_id as id, name from activity;`; +export const getActivitySQL = (): SQLStatement => + SQL`SELECT activity_id as id, name from activity where record_end_date is null;`; /** - * SQL query to fetch common survey methodology codes. + * SQL query to fetch field method codes. * * @returns {SQLStatement} sql query object */ -export const getCommonSurveyMethodologiesSQL = (): SQLStatement => - SQL`SELECT common_survey_methodology_id as id, name from common_survey_methodology;`; +export const getFieldMethodsSQL = (): SQLStatement => + SQL`SELECT field_method_id as id, name from field_method where record_end_date is null;`; + +/** + * SQL query to fetch ecological season codes. + * + * @returns {SQLStatement} sql query object + */ +export const getEcologicalSeasonsSQL = (): SQLStatement => + SQL`SELECT ecological_season_id as id, name from ecological_season where record_end_date is null;`; + +/** + * SQL query to fetch vantage codes. + * + * @returns {SQLStatement} sql query object + */ +export const getVantageCodesSQL = (): SQLStatement => + SQL`SELECT vantage_id as id, name from vantage where record_end_date is null;`; + +/** + * SQL query to intended outcomes codes. + * + * @returns {SQLStatement} sql query object + */ +export const getIntendedOutcomesSQL = (): SQLStatement => + SQL`SELECT intended_outcome_id as id, name from intended_outcome where record_end_date is null;`; /** * SQL query to fetch project type codes. * * @returns {SQLStatement} sql query object */ -export const getProjectTypeSQL = (): SQLStatement => SQL`SELECT project_type_id as id, name from project_type;`; +export const getProjectTypeSQL = (): SQLStatement => + SQL`SELECT project_type_id as id, name from project_type where record_end_date is null;`; /** * SQL query to fetch investment action category codes. @@ -60,7 +86,7 @@ export const getProjectTypeSQL = (): SQLStatement => SQL`SELECT project_type_id * @returns {SQLStatement} sql query object */ export const getInvestmentActionCategorySQL = (): SQLStatement => - SQL`SELECT investment_action_category_id as id, funding_source_id as fs_id, name from investment_action_category ORDER BY name ASC;`; + SQL`SELECT investment_action_category_id as id, funding_source_id as fs_id, name from investment_action_category where record_end_date is null ORDER BY name ASC;`; /** * SQL query to fetch IUCN conservation action level 1 classification codes. @@ -68,7 +94,7 @@ export const getInvestmentActionCategorySQL = (): SQLStatement => * @returns {SQLStatement} sql query object */ export const getIUCNConservationActionLevel1ClassificationSQL = (): SQLStatement => - SQL`SELECT iucn_conservation_action_level_1_classification_id as id, name from iucn_conservation_action_level_1_classification;`; + SQL`SELECT iucn_conservation_action_level_1_classification_id as id, name from iucn_conservation_action_level_1_classification where record_end_date is null;`; /** * SQL query to fetch IUCN conservation action level 2 sub-classification codes. @@ -76,7 +102,7 @@ export const getIUCNConservationActionLevel1ClassificationSQL = (): SQLStatement * @returns {SQLStatement} sql query object */ export const getIUCNConservationActionLevel2SubclassificationSQL = (): SQLStatement => - SQL`SELECT iucn_conservation_action_level_2_subclassification_id as id, iucn_conservation_action_level_1_classification_id as iucn1_id, name from iucn_conservation_action_level_2_subclassification;`; + SQL`SELECT iucn_conservation_action_level_2_subclassification_id as id, iucn_conservation_action_level_1_classification_id as iucn1_id, name from iucn_conservation_action_level_2_subclassification where record_end_date is null;`; /** * SQL query to fetch IUCN conservation action level 3 sub-classification codes. @@ -84,21 +110,23 @@ export const getIUCNConservationActionLevel2SubclassificationSQL = (): SQLStatem * @returns {SQLStatement} sql query object */ export const getIUCNConservationActionLevel3SubclassificationSQL = (): SQLStatement => - SQL`SELECT iucn_conservation_action_level_3_subclassification_id as id, iucn_conservation_action_level_2_subclassification_id as iucn2_id, name from iucn_conservation_action_level_3_subclassification;`; + SQL`SELECT iucn_conservation_action_level_3_subclassification_id as id, iucn_conservation_action_level_2_subclassification_id as iucn2_id, name from iucn_conservation_action_level_3_subclassification where record_end_date is null;`; /** * SQL query to fetch system role codes. * * @returns {SQLStatement} sql query object */ -export const getSystemRolesSQL = (): SQLStatement => SQL`SELECT system_role_id as id, name from system_role;`; +export const getSystemRolesSQL = (): SQLStatement => + SQL`SELECT system_role_id as id, name from system_role where record_end_date is null;`; /** * SQL query to fetch project role codes. * * @returns {SQLStatement} sql query object */ -export const getProjectRolesSQL = (): SQLStatement => SQL`SELECT project_role_id as id, name from project_role;`; +export const getProjectRolesSQL = (): SQLStatement => + SQL`SELECT project_role_id as id, name from project_role where record_end_date is null;`; /** * SQL query to fetch administrative activity status type codes. @@ -106,7 +134,7 @@ export const getProjectRolesSQL = (): SQLStatement => SQL`SELECT project_role_id * @returns {SQLStatement} sql query object */ export const getAdministrativeActivityStatusTypeSQL = (): SQLStatement => - SQL`SELECT administrative_activity_status_type_id as id, name FROM administrative_activity_status_type;`; + SQL`SELECT administrative_activity_status_type_id as id, name FROM administrative_activity_status_type where record_end_date is null;`; /** * SQL query to fetch taxon codes. @@ -122,7 +150,7 @@ export const getTaxonsSQL = (): SQLStatement => wldtaxonomic_units WHERE tty_name = 'SPECIES' - and + and end_date is null ORDER BY name;`; diff --git a/api/src/services/code-service.ts b/api/src/services/code-service.ts index 7c3e63dc57..7909e22d9e 100644 --- a/api/src/services/code-service.ts +++ b/api/src/services/code-service.ts @@ -39,7 +39,10 @@ export interface IAllCodeSets { project_roles: CodeSet; regional_offices: CodeSet; administrative_activity_status_type: CodeSet; - common_survey_methodologies: CodeSet; + field_methods: CodeSet; + ecological_seasons: CodeSet; + intended_outcomes: CodeSet; + vantage_codes: CodeSet; } export class CodeService extends DBService { @@ -67,7 +70,10 @@ export class CodeService extends DBService { project_roles, administrative_activity_status_type, species, - common_survey_methodologies + field_methods, + ecological_seasons, + intended_outcomes, + vantage_codes ] = await Promise.all([ await this.connection.query(queries.codes.getManagementActionTypeSQL().text), await this.connection.query(queries.codes.getFirstNationsSQL().text), @@ -83,7 +89,12 @@ export class CodeService extends DBService { await this.connection.query(queries.codes.getProjectRolesSQL().text), await this.connection.query(queries.codes.getAdministrativeActivityStatusTypeSQL().text), await this.connection.query(queries.codes.getTaxonsSQL().text), - await this.connection.query(queries.codes.getCommonSurveyMethodologiesSQL().text) + await this.connection.query(queries.codes.getFieldMethodsSQL().text), + await this.connection.query(queries.codes.getEcologicalSeasonsSQL().text), + + await this.connection.query(queries.codes.getIntendedOutcomesSQL().text), + + await this.connection.query(queries.codes.getVantageCodesSQL().text) ]); return { @@ -109,7 +120,11 @@ export class CodeService extends DBService { administrative_activity_status_type: (administrative_activity_status_type && administrative_activity_status_type.rows) || [], species: (species && species.rows) || [], - common_survey_methodologies: (common_survey_methodologies && common_survey_methodologies.rows) || [], + field_methods: (field_methods && field_methods.rows) || [], + ecological_seasons: (ecological_seasons && ecological_seasons.rows) || [], + intended_outcomes: (intended_outcomes && intended_outcomes.rows) || [], + vantage_codes: (vantage_codes && vantage_codes.rows) || [], + // TODO Temporarily hard coded list of code values below coordinator_agency, region, diff --git a/app/src/features/surveys/CreateSurveyPage.tsx b/app/src/features/surveys/CreateSurveyPage.tsx index 09346c992e..838a6f618b 100644 --- a/app/src/features/surveys/CreateSurveyPage.tsx +++ b/app/src/features/surveys/CreateSurveyPage.tsx @@ -359,7 +359,7 @@ const CreateSurveyPage = () => { }) || [] } common_survey_methodologies={ - codes?.common_survey_methodologies?.map((item) => { + codes?.field_method?.map((item) => { return { value: item.id, label: item.name }; }) || [] } diff --git a/app/src/features/surveys/view/components/SurveyGeneralInformation.tsx b/app/src/features/surveys/view/components/SurveyGeneralInformation.tsx index 4e78df0f89..fbc3fd1ed3 100644 --- a/app/src/features/surveys/view/components/SurveyGeneralInformation.tsx +++ b/app/src/features/surveys/view/components/SurveyGeneralInformation.tsx @@ -175,7 +175,7 @@ const SurveyGeneralInformation: React.FC = (prop }) || [] } common_survey_methodologies={ - codes?.common_survey_methodologies?.map((item) => { + codes?.field_method?.map((item) => { return { value: item.id, label: item.name }; }) || [] } diff --git a/app/src/interfaces/useCodesApi.interface.ts b/app/src/interfaces/useCodesApi.interface.ts index 0ba7555a8f..2aa6ab808c 100644 --- a/app/src/interfaces/useCodesApi.interface.ts +++ b/app/src/interfaces/useCodesApi.interface.ts @@ -38,5 +38,5 @@ export interface IGetAllCodeSetsResponse { project_roles: CodeSet; regional_offices: CodeSet; administrative_activity_status_type: CodeSet; - common_survey_methodologies: CodeSet; + field_method: CodeSet; } diff --git a/app/src/test-helpers/code-helpers.ts b/app/src/test-helpers/code-helpers.ts index 429600e297..bfc63ceaa7 100644 --- a/app/src/test-helpers/code-helpers.ts +++ b/app/src/test-helpers/code-helpers.ts @@ -40,7 +40,7 @@ export const codes: IGetAllCodeSetsResponse = { { id: 2, name: 'Actioned' }, { id: 3, name: 'Rejected' } ], - common_survey_methodologies: [ + field_method: [ { id: 1, name: 'Recruitment' }, { id: 2, name: 'SRB' } ] From 4bc94133f6106f2d4d7218084947ed6d8d2705e6 Mon Sep 17 00:00:00 2001 From: Anissa Agahchen Date: Wed, 6 Apr 2022 11:27:42 -0700 Subject: [PATCH 07/66] create queries working with vantage code as a single item to enter in the survey table --- api/src/models/survey-create.ts | 15 ++- api/src/models/survey-view-update.ts | 24 ++++ api/src/models/survey-view.ts | 9 +- api/src/openapi/schemas/survey.ts | 21 +++- .../project/{projectId}/survey/create.ts | 30 +++++ .../{projectId}/survey/{surveyId}/update.ts | 31 ++++- .../{projectId}/survey/{surveyId}/view.ts | 34 +++++- .../queries/survey/survey-create-queries.ts | 50 +++++++- api/src/queries/survey/survey-view-queries.ts | 21 ++-- .../survey/survey-view-update-queries.ts | 49 +++++++- app/src/features/surveys/CreateSurveyPage.tsx | 57 +++------ .../components/PurposeAndMethodologyForm.tsx | 108 +++++++++++------- .../features/surveys/view/SurveyDetails.tsx | 21 ++-- .../SurveyPurposeAndMethodology.tsx | 51 +++++---- app/src/hooks/api/useSurveyApi.ts | 2 + app/src/interfaces/useCodesApi.interface.ts | 5 +- app/src/interfaces/useSurveyApi.interface.ts | 16 +-- app/src/test-helpers/code-helpers.ts | 14 ++- .../migrations/20220404093900_SIMS.1.1.0.ts | 18 +-- 19 files changed, 419 insertions(+), 157 deletions(-) diff --git a/api/src/models/survey-create.ts b/api/src/models/survey-create.ts index 4ac65145e9..caead0ad62 100644 --- a/api/src/models/survey-create.ts +++ b/api/src/models/survey-create.ts @@ -17,12 +17,16 @@ export class PostSurveyObject { sedis_procedures_accepted: boolean; focal_species: number[]; ancillary_species: number[]; - common_survey_methodology_id: number; + field_method_id: number; + ecological_season_id: number; + // vantage_codes: number[]; + vantage_id: number; start_date: string; end_date: string; survey_area_name: string; survey_data_proprietary: boolean; - intended_outcome: string; + intended_outcome_id: number; + additional_details: string; geometry: Feature[]; permit_number: string; permit_type: string; @@ -48,7 +52,7 @@ export class PostSurveyObject { this.sedis_procedures_accepted = obj?.sedis_procedures_accepted === 'true' || false; this.focal_species = (obj?.focal_species?.length && obj.focal_species) || []; this.ancillary_species = (obj?.ancillary_species?.length && obj.ancillary_species) || []; - this.common_survey_methodology_id = obj?.common_survey_methodology_id || null; + this.field_method_id = obj?.field_method_id || null; this.start_date = obj?.start_date || null; this.survey_area_name = obj?.survey_area_name || null; this.permit_number = obj?.permit_number || null; @@ -56,7 +60,10 @@ export class PostSurveyObject { this.funding_sources = (obj?.funding_sources?.length && obj.funding_sources) || []; this.survey_data_proprietary = obj?.survey_data_proprietary === 'true' || false; this.survey_name = obj?.survey_name || null; - this.intended_outcome = obj?.intended_outcome || null; + this.intended_outcome_id = obj?.intended_outcome_id || null; + this.ecological_season_id = obj?.ecological_season_id || null; + this.additional_details = obj?.additional_details || null; + this.vantage_id = obj?.vantage_id || null; this.geometry = (obj?.geometry?.length && obj.geometry) || []; this.survey_proprietor = (obj && obj.survey_data_proprietary === 'true' && new PostSurveyProprietorData(obj)) || undefined; diff --git a/api/src/models/survey-view-update.ts b/api/src/models/survey-view-update.ts index 4f20d5d3f6..5d4e7ed681 100644 --- a/api/src/models/survey-view-update.ts +++ b/api/src/models/survey-view-update.ts @@ -39,3 +39,27 @@ export class GetSurveyProprietorData { this.revision_count = data?.revision_count ?? null; } } + +export class GetSurveyPurposeAndMethodologyData { + id: number; + intended_outcome_id: number; + additional_details: string; + ecological_season_id: number; + vantage_id: number; + revision_count: number; + + constructor(data?: any) { + defaultLog.debug({ + label: 'GetSurveyPurposeAndMethodologyData', + message: 'params', + surveyProprietorData: data + }); + + this.id = data?.id ?? null; + this.intended_outcome_id = data?.intended_outcome_id ?? null; + this.additional_details = data?.additional_details ?? null; + this.ecological_season_id = data?.ecological_season_id ?? null; + this.vantage_id = data?.vantage_id ?? null; + this.revision_count = data?.revision_count ?? null; + } +} diff --git a/api/src/models/survey-view.ts b/api/src/models/survey-view.ts index bd67c49027..ac5d63fc27 100644 --- a/api/src/models/survey-view.ts +++ b/api/src/models/survey-view.ts @@ -17,7 +17,6 @@ export class GetViewSurveyDetailsData { survey_purpose: string; focal_species: (string | number)[]; ancillary_species: (string | number)[]; - common_survey_methodology: string; start_date: string; end_date: string; biologist_first_name: string; @@ -53,7 +52,6 @@ export class GetViewSurveyDetailsData { this.start_date = surveyDetailsData?.start_date || ''; this.end_date = surveyDetailsData?.end_date || ''; this.biologist_first_name = surveyDetailsData?.lead_first_name || ''; - this.common_survey_methodology = surveyDetailsData?.common_survey_methodology || ''; this.biologist_last_name = surveyDetailsData?.lead_last_name || ''; this.survey_area_name = surveyDetailsData?.location_name || ''; this.geometry = (surveyDetailsData?.geometry?.length && surveyDetailsData.geometry) || []; @@ -71,6 +69,13 @@ export class GetViewSurveyDetailsData { } } +/** + * Pre-processes GET /project/{projectId}/survey/{surveyId} survey details data for view + * + * @export + * @class GetViewSurveyDetailsData + */ + /** * Pre-processes GET surveys list data * diff --git a/api/src/openapi/schemas/survey.ts b/api/src/openapi/schemas/survey.ts index 6b872e8fbd..934a86eee3 100644 --- a/api/src/openapi/schemas/survey.ts +++ b/api/src/openapi/schemas/survey.ts @@ -10,7 +10,11 @@ export const surveyCreatePostRequestObject = { 'end_date', 'focal_species', 'ancillary_species', - 'intended_outcome', + 'intended_outcome_id', + 'additional_details', + 'field_method_id', + 'vantage_id', + 'ecological_season_id', 'biologist_first_name', 'biologist_last_name', 'survey_area_name', @@ -42,9 +46,22 @@ export const surveyCreatePostRequestObject = { }, description: 'Selected ancillary species ids' }, - intended_outcome: { + + intended_outcome_id: { + type: 'number' + }, + additional_details: { type: 'string' }, + field_method_id: { + type: 'number' + }, + vantage_id: { + type: 'number' + }, + ecological_season_id: { + type: 'number' + }, biologist_first_name: { type: 'string' }, diff --git a/api/src/paths/project/{projectId}/survey/create.ts b/api/src/paths/project/{projectId}/survey/create.ts index a3d45b691d..eff452db17 100644 --- a/api/src/paths/project/{projectId}/survey/create.ts +++ b/api/src/paths/project/{projectId}/survey/create.ts @@ -169,6 +169,15 @@ export function createSurvey(): RequestHandler { sanitizedPostSurveyData.survey_proprietor && promises.push(insertSurveyProprietor(sanitizedPostSurveyData.survey_proprietor, surveyId, connection)); + // Handle vantage codes associated to this survey + // promises.push( + // Promise.all( + // sanitizedPostSurveyData.vantage_codes.map((vantageCode: number) => + // insertAncillarySpecies(vantageCode, surveyId, connection) + // ) + // ) + // ); + await Promise.all(promises); await connection.commit(); @@ -229,6 +238,27 @@ export const insertAncillarySpecies = async ( return result.id; }; +// export const insertVantageCodes = async ( +// vantage_code_id: number, +// survey_id: number, +// connection: IDBConnection +// ): Promise => { +// const sqlStatement = queries.survey.postVantageCodesSQL(vantage_code_id, survey_id); + +// if (!sqlStatement) { +// throw new HTTP400('Failed to build SQL insert statement'); +// } + +// const response = await connection.query(sqlStatement.text, sqlStatement.values); +// const result = (response && response.rows && response.rows[0]) || null; + +// if (!result || !result.id) { +// throw new HTTP400('Failed to insert ancillary species data'); +// } + +// return result.id; +// }; + export const insertSurveyProprietor = async ( survey_proprietor: PostSurveyProprietorData, survey_id: number, diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts index 18960c9364..95b204a046 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts @@ -9,7 +9,7 @@ import { PutSurveyDetailsData, PutSurveyProprietorData } from '../../../../../models/survey-update'; -import { GetSurveyProprietorData } from '../../../../../models/survey-view-update'; +import { GetSurveyProprietorData, GetSurveyPurposeAndMethodologyData } from '../../../../../models/survey-view-update'; import { surveyIdResponseObject, surveyUpdateGetResponseObject, @@ -22,6 +22,7 @@ import { insertAncillarySpecies, insertFocalSpecies, insertSurveyFundingSource, export interface IUpdateSurvey { survey_details: object | null; + survey_purpose_and_methodology: object | null; survey_proprietor: object | null; } @@ -59,6 +60,7 @@ export const PUT: Operation = [ export enum GET_SURVEY_ENTITIES { survey_details = 'survey_details', + survey_purpose_and_methodology = 'survey_purpose_and_methodology', survey_proprietor = 'survey_proprietor' } @@ -197,6 +199,7 @@ PUT.apiDoc = { export interface IGetSurveyForUpdate { survey_details: GetUpdateSurveyDetailsData | null; + survey_purpose_and_methodology: GetSurveyPurposeAndMethodologyData | null; survey_proprietor: GetSurveyProprietorData | null; } @@ -222,6 +225,7 @@ export function getSurveyForUpdate(): RequestHandler { const results: IGetSurveyForUpdate = { survey_details: null, + survey_purpose_and_methodology: null, survey_proprietor: null }; @@ -235,6 +239,14 @@ export function getSurveyForUpdate(): RequestHandler { ); } + if (entities.includes(GET_SURVEY_ENTITIES.survey_purpose_and_methodology)) { + promises.push( + getSurveyPurposeAndMethodologyData(surveyId, connection).then((value) => { + results.survey_purpose_and_methodology = value; + }) + ); + } + if (entities.includes(GET_SURVEY_ENTITIES.survey_proprietor)) { promises.push( getSurveyProprietorData(surveyId, connection).then((value) => { @@ -278,6 +290,23 @@ export const getSurveyDetailsData = async ( return result; }; +export const getSurveyPurposeAndMethodologyData = async ( + surveyId: number, + connection: IDBConnection +): Promise => { + const sqlStatement = queries.survey.getSurveyPurposeAndMethodologyForUpdateSQL(surveyId); + + if (!sqlStatement) { + throw new HTTP400('Failed to build survey proprietor SQL get statement'); + } + + const response = await connection.query(sqlStatement.text, sqlStatement.values); + + return ( + (response && response.rows && response.rows[0] && new GetSurveyPurposeAndMethodologyData(response.rows[0])) || null + ); +}; + export const getSurveyProprietorData = async ( surveyId: number, connection: IDBConnection diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts index cb0640bd85..62a88aa5a9 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts @@ -4,7 +4,7 @@ import { PROJECT_ROLE } from '../../../../../constants/roles'; import { getDBConnection, IDBConnection } from '../../../../../database/db'; import { HTTP400 } from '../../../../../errors/custom-error'; import { GetViewSurveyDetailsData } from '../../../../../models/survey-view'; -import { GetSurveyProprietorData } from '../../../../../models/survey-view-update'; +import { GetSurveyProprietorData, GetSurveyPurposeAndMethodologyData } from '../../../../../models/survey-view-update'; import { surveyViewGetResponseObject } from '../../../../../openapi/schemas/survey'; import { queries } from '../../../../../queries/queries'; import { authorizeRequestHandler } from '../../../../../request-handlers/security/authorization'; @@ -100,8 +100,15 @@ export function getSurveyForView(): RequestHandler { try { await connection.open(); - const [surveyBasicData, surveyFundingSourcesData, SurveySpeciesData, surveyProprietorData] = await Promise.all([ + const [ + surveyBasicData, + surveyPurposeAndMethodology, + surveyFundingSourcesData, + SurveySpeciesData, + surveyProprietorData + ] = await Promise.all([ getSurveyBasicDataForView(surveyId, connection), + getSurveyPurposeAndMethodologyDataForView(surveyId, connection), getSurveyFundingSourcesDataForView(surveyId, connection), getSurveySpeciesDataForView(surveyId, connection), getSurveyProprietorDataForView(surveyId, connection) @@ -115,11 +122,15 @@ export function getSurveyForView(): RequestHandler { ...SurveySpeciesData }); + const getSurveyPurposeAndMethodology = + (surveyPurposeAndMethodology && new GetSurveyPurposeAndMethodologyData(surveyPurposeAndMethodology)) || null; + const getSurveyProprietorData = (surveyProprietorData && new GetSurveyProprietorData(surveyProprietorData)) || null; const result = { survey_details: getSurveyData, + survey_purpose_and_methodology: getSurveyPurposeAndMethodology, survey_proprietor: getSurveyProprietorData }; @@ -149,6 +160,25 @@ export const getSurveyBasicDataForView = async (surveyId: number, connection: ID return (response && response.rows?.[0]) || null; }; +export const getSurveyPurposeAndMethodologyDataForView = async ( + surveyId: number, + connection: IDBConnection +): Promise => { + const sqlStatement = queries.survey.getSurveyPurposeAndMethodologyForUpdateSQL(surveyId); + + if (!sqlStatement) { + throw new HTTP400('Failed to build SQL get statement'); + } + + const response = await connection.query(sqlStatement.text, sqlStatement.values); + + if (!response || !response?.rows?.[0]) { + throw new HTTP400('Failed to get survey purpose and methodology data'); + } + + return (response && response.rows?.[0]) || null; +}; + export const getSurveyFundingSourcesDataForView = async ( surveyId: number, connection: IDBConnection diff --git a/api/src/queries/survey/survey-create-queries.ts b/api/src/queries/survey/survey-create-queries.ts index ef3a559497..3480bd0520 100644 --- a/api/src/queries/survey/survey-create-queries.ts +++ b/api/src/queries/survey/survey-create-queries.ts @@ -24,30 +24,38 @@ export const postSurveySQL = (projectId: number, survey: PostSurveyObject): SQLS return null; } + //TODO: Vantage codes have a 1:many relationship. Need the model to reflect + const sqlStatement: SQLStatement = SQL` INSERT INTO survey ( project_id, name, - objectives, + additional_details, + ecological_season_id, + intended_outcome_id, + vantage_id, start_date, end_date, lead_first_name, lead_last_name, location_name, geojson, - common_survey_methodology_id, + field_method_id, geography ) VALUES ( ${projectId}, ${survey.survey_name}, - ${survey.intended_outcome}, + ${survey.additional_details}, + ${survey.ecological_season_id}, + ${survey.intended_outcome_id}, + ${survey.vantage_id}, ${survey.start_date}, ${survey.end_date}, ${survey.biologist_first_name}, ${survey.biologist_last_name}, ${survey.survey_area_name}, ${JSON.stringify(survey.geometry)}, - ${survey.common_survey_methodology_id} + ${survey.field_method_id} `; if (survey.geometry && survey.geometry.length) { @@ -305,3 +313,37 @@ export const postAncillarySpeciesSQL = (speciesId: number, surveyId: number): SQ return sqlStatement; }; + +/** + * SQL query to insert a ancillary species row into the study_species table. + * + * @param {number} speciesId + * @param {number} surveyId + * @returns {SQLStatement} sql query object + */ +// export const postVantageCodesSQL = (vantageCodeId: number, surveyId: number): SQLStatement | null => { +// defaultLog.debug({ label: 'postVantageCodesSQL', message: 'params', vantageCodeId, surveyId }); + +// if (!vantageCodeId || !surveyId) { +// return null; +// } + +// const sqlStatement: SQLStatement = SQL` +// INSERT INTO some_table ( +// vantage_code_id, +// survey_id +// ) VALUES ( +// ${vantageCodeId}, +// ${surveyId} +// ) RETURNING some_table_id as id; +// `; + +// defaultLog.debug({ +// label: 'postVantageCodesSQL', +// message: 'sql', +// 'sqlStatement.text': sqlStatement.text, +// 'sqlStatement.values': sqlStatement.values +// }); + +// return sqlStatement; +// }; diff --git a/api/src/queries/survey/survey-view-queries.ts b/api/src/queries/survey/survey-view-queries.ts index 66dc564b07..64d9596c04 100644 --- a/api/src/queries/survey/survey-view-queries.ts +++ b/api/src/queries/survey/survey-view-queries.ts @@ -145,7 +145,11 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n SELECT s.survey_id as id, s.name, - s.objectives, + s.additional_details, + s.field_method_id, + s.ecological_season_id, + s.intended_outcome_id, + s.vantage_id, s.start_date, s.end_date, s.lead_first_name, @@ -156,7 +160,6 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n s.publish_timestamp as publish_date, per.number, per.type, - csm.name as common_survey_methodology, max(os.occurrence_submission_id) as occurrence_submission_id, max(sss.survey_summary_submission_id) as survey_summary_submission_id FROM @@ -166,9 +169,9 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n ON per.survey_id = s.survey_id LEFT OUTER JOIN - common_survey_methodology as csm + field_method as fm ON - csm.common_survey_methodology_id = s.common_survey_methodology_id + fm.field_method_id = s.field_method_id LEFT OUTER JOIN occurrence_submission as os ON @@ -182,7 +185,11 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n GROUP BY s.survey_id, s.name, - s.objectives, + s.field_method_id, + s.additional_details, + s.intended_outcome_id, + s.ecological_season_id, + s.vantage_id, s.start_date, s.end_date, s.lead_first_name, @@ -192,8 +199,7 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n s.revision_count, s.publish_timestamp, per.number, - per.type, - csm.name; + per.type; `; defaultLog.debug({ @@ -212,7 +218,6 @@ export const getSurveyFundingSourcesDataForViewSQL = (surveyId: number): SQLStat message: 'params', surveyId }); - if (!surveyId) { return null; } diff --git a/api/src/queries/survey/survey-view-update-queries.ts b/api/src/queries/survey/survey-view-update-queries.ts index cf125e2437..8e7cd497b5 100644 --- a/api/src/queries/survey/survey-view-update-queries.ts +++ b/api/src/queries/survey/survey-view-update-queries.ts @@ -24,7 +24,7 @@ export const getSurveyDetailsForUpdateSQL = (surveyId: number): SQLStatement | n SELECT s.survey_id as id, s.name, - s.objectives, + s.additional_details, s.start_date, s.end_date, s.lead_first_name, @@ -32,7 +32,7 @@ export const getSurveyDetailsForUpdateSQL = (surveyId: number): SQLStatement | n s.location_name, s.geojson as geometry, s.revision_count, - s.common_survey_methodology_id, + s.field_method_id, s.publish_timestamp as publish_date, per.number, per.type, @@ -83,7 +83,7 @@ export const getSurveyDetailsForUpdateSQL = (surveyId: number): SQLStatement | n group by s.survey_id, s.name, - s.objectives, + s.additional_details, s.start_date, s.end_date, s.lead_first_name, @@ -91,7 +91,7 @@ export const getSurveyDetailsForUpdateSQL = (surveyId: number): SQLStatement | n s.location_name, s.geojson, s.revision_count, - s.common_survey_methodology_id, + s.field_method_id, s.publish_timestamp, per.number, per.type; @@ -158,3 +158,44 @@ export const getSurveyProprietorForUpdateSQL = (surveyId: number): SQLStatement return sqlStatement; }; + +/** + * SQL query to retrieve a survey_proprietor row. + * + * @param {number} surveyId + * @returns {SQLStatement} sql query object + */ +export const getSurveyPurposeAndMethodologyForUpdateSQL = (surveyId: number): SQLStatement | null => { + defaultLog.debug({ + label: 'getSurveyPurposeAndMethodologyForUpdateSQL', + message: 'params', + surveyId + }); + + if (!surveyId) { + return null; + } + + const sqlStatement = SQL` + SELECT + s.survey_id as id, + s.field_method_id, + s.additional_details, + s.ecological_season_id, + s.intended_outcome_id, + s.vantage_id + FROM + survey s + WHERE + survey_id = ${surveyId}; + `; + + defaultLog.debug({ + label: 'getSurveyPurposeAndMethodologyForUpdateSQL', + message: 'sql', + 'sqlStatement.text': sqlStatement.text, + 'sqlStatement.values': sqlStatement.values + }); + + return sqlStatement; +}; diff --git a/app/src/features/surveys/CreateSurveyPage.tsx b/app/src/features/surveys/CreateSurveyPage.tsx index 881e3c9f52..29ffd85cb3 100644 --- a/app/src/features/surveys/CreateSurveyPage.tsx +++ b/app/src/features/surveys/CreateSurveyPage.tsx @@ -10,15 +10,23 @@ import { Theme } from '@material-ui/core/styles/createMuiTheme'; import makeStyles from '@material-ui/core/styles/makeStyles'; import Typography from '@material-ui/core/Typography'; import { IErrorDialogProps } from 'components/dialog/ErrorDialog'; +import HorizontalSplitFormComponent from 'components/fields/HorizontalSplitFormComponent'; +import { DATE_FORMAT, DATE_LIMIT } from 'constants/dateTimeFormats'; import { CreateSurveyI18N } from 'constants/i18n'; +import { DialogContext } from 'contexts/dialogContext'; import { Formik, FormikProps } from 'formik'; +import * as History from 'history'; +import { APIError } from 'hooks/api/useAxios'; import { useBiohubApi } from 'hooks/useBioHubApi'; import { IGetAllCodeSetsResponse } from 'interfaces/useCodesApi.interface'; import { IGetProjectForViewResponse } from 'interfaces/useProjectApi.interface'; import { ICreateSurveyRequest, SurveyFundingSources, SurveyPermits } from 'interfaces/useSurveyApi.interface'; +import moment from 'moment'; import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { Prompt, useHistory, useParams } from 'react-router'; import { validateFormFieldsAndReportCompletion } from 'utils/customValidation'; +import { getFormattedAmount, getFormattedDate, getFormattedDateRangeString } from 'utils/Utils'; +import yup from 'utils/YupSchema'; import AgreementsForm, { AgreementsInitialValues, AgreementsYupSchema } from './components/AgreementsForm'; import GeneralInformationForm, { GeneralInformationInitialValues, @@ -28,16 +36,11 @@ import ProprietaryDataForm, { ProprietaryDataInitialValues, ProprietaryDataYupSchema } from './components/ProprietaryDataForm'; +import PurposeAndMethodologyForm, { + PurposeAndMethodologyInitialValues, + PurposeAndMethodologyYupSchema +} from './components/PurposeAndMethodologyForm'; import StudyAreaForm, { StudyAreaInitialValues, StudyAreaYupSchema } from './components/StudyAreaForm'; -import HorizontalSplitFormComponent from 'components/fields/HorizontalSplitFormComponent'; -import * as History from 'history'; -import { APIError } from 'hooks/api/useAxios'; -import { DialogContext } from 'contexts/dialogContext'; -import yup from 'utils/YupSchema'; -import { DATE_FORMAT, DATE_LIMIT } from 'constants/dateTimeFormats'; -import moment from 'moment'; -import { getFormattedAmount, getFormattedDate, getFormattedDateRangeString } from 'utils/Utils'; -import PurposeAndMethologyForm from './components/PurposeAndMethodologyForm'; const useStyles = makeStyles((theme: Theme) => ({ actionButton: { @@ -93,30 +96,6 @@ const CreateSurveyPage = () => { const [surveyFundingSources, setSurveyFundingSources] = useState([]); const [formikRef] = useState(useRef>(null)); - const intended_outcomes = [ - { id: 1, name: 'intended outcome 1' }, - { id: 2, name: 'intended outcome 2' }, - { id: 3, name: 'intended outcome 3' } - ]; - - const ecological_seasons = [ - { id: 1, name: 'ecological season 1' }, - { id: 2, name: 'ecological season 2' }, - { id: 3, name: 'ecological season 3' } - ]; - - const vantage_codes = [ - { id: 1, name: 'vantage code 1' }, - { id: 2, name: 'vantage code 2' }, - { id: 3, name: 'vantage code 3' } - ]; - - const field_methods = [ - { id: 1, name: 'method 1' }, - { id: 2, name: 'method 2' }, - { id: 3, name: 'method 3' } - ]; - // Ability to bypass showing the 'Are you sure you want to cancel' dialog const [enableCancelCheck, setEnableCancelCheck] = useState(true); @@ -142,6 +121,7 @@ const CreateSurveyPage = () => { const [surveyInitialValues] = useState({ ...GeneralInformationInitialValues, ...StudyAreaInitialValues, + ...PurposeAndMethodologyInitialValues, ...ProprietaryDataInitialValues, ...AgreementsInitialValues }); @@ -183,6 +163,7 @@ const CreateSurveyPage = () => { ) }) .concat(StudyAreaYupSchema) + .concat(PurposeAndMethodologyYupSchema) .concat(ProprietaryDataYupSchema) .concat(AgreementsYupSchema); @@ -413,24 +394,24 @@ const CreateSurveyPage = () => { title="Purpose And Methodology" summary="" component={ - { + codes?.intended_outcomes?.map((item) => { return { value: item.id, label: item.name }; }) || [] } field_methods={ - field_methods.map((item) => { + codes?.field_methods?.map((item) => { return { value: item.id, label: item.name }; }) || [] } ecological_seasons={ - ecological_seasons.map((item) => { + codes?.ecological_seasons.map((item) => { return { value: item.id, label: item.name }; }) || [] } vantage_codes={ - vantage_codes.map((item) => { + codes?.vantage_codes?.map((item) => { return { value: item.id, label: item.name }; }) || [] } diff --git a/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx b/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx index be7cefb219..2340fa9125 100644 --- a/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx +++ b/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx @@ -9,7 +9,7 @@ import Select from '@material-ui/core/Select'; //import Typography from '@material-ui/core/Typography'; import { IAutocompleteFieldOption } from 'components/fields/AutocompleteField'; import CustomTextField from 'components/fields/CustomTextField'; -import MultiAutocompleteFieldVariableSize from 'components/fields/MultiAutocompleteFieldVariableSize'; +//import MultiAutocompleteFieldVariableSize from 'components/fields/MultiAutocompleteFieldVariableSize'; //import { IMultiAutocompleteFieldOption } from 'components/fields/MultiAutocompleteField'; //import MultiAutocompleteFieldVariableSize from 'components/fields/MultiAutocompleteFieldVariableSize'; import { useFormikContext } from 'formik'; @@ -17,30 +17,28 @@ import React from 'react'; import yup from 'utils/YupSchema'; export interface IPurposeAndMethodologyForm { - intended_outcome: number; + intended_outcome_id: number; additional_details: string; - field_method: number; - ecological_season: number; - vantage_codes: number[]; + field_method_id: number; + ecological_season_id: number; + vantage_id: number; } export const PurposeAndMethodologyInitialValues: IPurposeAndMethodologyForm = { - intended_outcome: ('' as unknown) as number, + intended_outcome_id: ('' as unknown) as number, additional_details: '', - field_method: ('' as unknown) as number, - ecological_season: ('' as unknown) as number, - vantage_codes: [] + field_method_id: ('' as unknown) as number, + ecological_season_id: ('' as unknown) as number, + vantage_id: ('' as unknown) as number }; -export const PurposeAndMethodologyYupSchema = (customYupRules?: any) => { - return yup.object().shape({ - field_method: yup.number().required('You must provide a field method'), - additional_details: yup.string(), - intended_outcome: yup.number().required('You must provide intended outcomes for the survey'), - ecological_season: yup.number().required('You must provide an ecological season for the survey'), - vantage_code: yup.array().min(1, 'You must specify a vantage code').required('Required') - }); -}; +export const PurposeAndMethodologyYupSchema = yup.object().shape({ + field_method_id: yup.number().required('You must provide a field method'), + additional_details: yup.string(), + intended_outcome_id: yup.number().required('You must provide intended outcomes for the survey'), + ecological_season_id: yup.number().required('You must provide an ecological season for the survey'), + vantage_id: yup.number().required('You must provide a vantage code for the survey') +}); export interface IPurposeAndMethodologyFormProps { intended_outcomes: IAutocompleteFieldOption[]; @@ -65,16 +63,16 @@ const PurposeAndMethologyForm: React.FC = (prop Purpose of Survey - Intended Outcomes + Intended Outcomes - {formikProps.touched.intended_outcome && formikProps.errors.intended_outcome} + {formikProps.touched.intended_outcome_id && formikProps.errors.intended_outcome_id} @@ -101,16 +99,16 @@ const PurposeAndMethologyForm: React.FC = (prop Survey Methodology - Field Method + Field Method - {formikProps.touched.field_method && formikProps.errors.field_method} + {formikProps.touched.field_method_id && formikProps.errors.field_method_id} + + + Survey Methodology + - Ecological Season + Ecological Season - {formikProps.touched.ecological_season && formikProps.errors.ecological_season} + {formikProps.touched.ecological_season_id && formikProps.errors.ecological_season_id} + + + Vantage Code + + {formikProps.touched.vantage_id && formikProps.errors.vantage_id} + + + + {/* +TODO://bring this back once we can do a multi-select - and have the database table to support it - + */} ); diff --git a/app/src/features/surveys/view/SurveyDetails.tsx b/app/src/features/surveys/view/SurveyDetails.tsx index a8332a09a7..d07f940fe5 100644 --- a/app/src/features/surveys/view/SurveyDetails.tsx +++ b/app/src/features/surveys/view/SurveyDetails.tsx @@ -24,6 +24,8 @@ export interface ISurveyDetailsProps { const SurveyDetails: React.FC = (props) => { const { surveyForViewData, codes, refresh, projectForViewData } = props; + console.log('survey for view data in the SurveyDetails', surveyForViewData); + return ( <> @@ -36,15 +38,16 @@ const SurveyDetails: React.FC = (props) => { refresh={refresh} /> - - - - + { + + + + } (null); const [purposeAndMethodologyFormData, setPurposeAndMethodologyFormData] = useState( @@ -99,7 +101,7 @@ const SurveyPurposeAndMethodologyData: React.FC { if (!survey_purpose_and_methodology) { - setSurveyDataForUpdate(null); + setSurveyPurposeAndMethodologyForUpdate(null); setPurposeAndMethodologyFormData(PurposeAndMethodologyInitialValues); setOpenEditDialog(true); return; @@ -112,6 +114,8 @@ const SurveyPurposeAndMethodologyData: React.FC } buttonOnClick={() => handleDialogEditOpen()} toolbarProps={{ disableGutters: true }} @@ -228,7 +231,7 @@ const SurveyPurposeAndMethodologyData: React.FC - Proprietor Name + Intended Outcome {survey_purpose_and_methodology.intended_outcome} @@ -236,7 +239,7 @@ const SurveyPurposeAndMethodologyData: React.FC - Data Category + Additional Details {'put the additional comments in here'} @@ -244,7 +247,7 @@ const SurveyPurposeAndMethodologyData: React.FC - DISA Required + Field Method {survey_purpose_and_methodology.field_method} @@ -252,7 +255,7 @@ const SurveyPurposeAndMethodologyData: React.FC - Category Rationale + Ecological Season {survey_purpose_and_methodology.ecological_season} @@ -261,7 +264,7 @@ const SurveyPurposeAndMethodologyData: React.FC - Category Rationale + Vantage Code {survey_purpose_and_methodology.vantage_codes} diff --git a/app/src/hooks/api/useSurveyApi.ts b/app/src/hooks/api/useSurveyApi.ts index 10dd06be0f..bbd4ed43a6 100644 --- a/app/src/hooks/api/useSurveyApi.ts +++ b/app/src/hooks/api/useSurveyApi.ts @@ -47,6 +47,8 @@ const useSurveyApi = (axios: AxiosInstance) => { const getSurveyForView = async (projectId: number, surveyId: number): Promise => { const { data } = await axios.get(`/api/project/${projectId}/survey/${surveyId}/view`); + console.log('survey for view: ', data); + return data; }; diff --git a/app/src/interfaces/useCodesApi.interface.ts b/app/src/interfaces/useCodesApi.interface.ts index 2aa6ab808c..1721773792 100644 --- a/app/src/interfaces/useCodesApi.interface.ts +++ b/app/src/interfaces/useCodesApi.interface.ts @@ -38,5 +38,8 @@ export interface IGetAllCodeSetsResponse { project_roles: CodeSet; regional_offices: CodeSet; administrative_activity_status_type: CodeSet; - field_method: CodeSet; + field_methods: CodeSet; + intended_outcomes: CodeSet; + ecological_seasons: CodeSet; + vantage_codes: CodeSet; } diff --git a/app/src/interfaces/useSurveyApi.interface.ts b/app/src/interfaces/useSurveyApi.interface.ts index 5cd5f41931..6f1b8f9c3d 100644 --- a/app/src/interfaces/useSurveyApi.interface.ts +++ b/app/src/interfaces/useSurveyApi.interface.ts @@ -24,11 +24,11 @@ export interface ICreateSurveyRequest { survey_area_name: string; survey_data_proprietary: string; survey_name: string; - intended_outcome: number; + intended_outcome_id: number; additional_details: string; - field_method: number; - ecological_season: number; - vantage_codes: number[]; + field_method_id: number; + ecological_season_id: number; + vantage_id: number; geometry: Feature[]; permit_number: string; } @@ -106,11 +106,11 @@ export interface IGetSurveyForUpdateResponseDetails { export interface IGetSurveyForUpdateResponsePurposeAndMethodology { id?: number; - intended_outcome: number; + intended_outcome_id: number; additional_details: string; - field_method: number; - ecological_season: number; - vantage_codes: number[]; + field_method_id: number; + ecological_season_id: number; + vantage_id: number; revision_count?: number; } diff --git a/app/src/test-helpers/code-helpers.ts b/app/src/test-helpers/code-helpers.ts index bfc63ceaa7..eb5b507b71 100644 --- a/app/src/test-helpers/code-helpers.ts +++ b/app/src/test-helpers/code-helpers.ts @@ -40,8 +40,20 @@ export const codes: IGetAllCodeSetsResponse = { { id: 2, name: 'Actioned' }, { id: 3, name: 'Rejected' } ], - field_method: [ + field_methods: [ { id: 1, name: 'Recruitment' }, { id: 2, name: 'SRB' } + ], + ecological_seasons: [ + { id: 1, name: 'Season 1' }, + { id: 2, name: 'Season 2' } + ], + vantage_codes: [ + { id: 1, name: 'Vantage Code 1' }, + { id: 2, name: 'Vantage Code 2' } + ], + intended_outcomes: [ + { id: 1, name: 'Intended Outcome 1' }, + { id: 2, name: 'Intended Outcome 2' } ] }; diff --git a/database/src/migrations/20220404093900_SIMS.1.1.0.ts b/database/src/migrations/20220404093900_SIMS.1.1.0.ts index 3660352394..89e6280f66 100644 --- a/database/src/migrations/20220404093900_SIMS.1.1.0.ts +++ b/database/src/migrations/20220404093900_SIMS.1.1.0.ts @@ -49,8 +49,8 @@ COMMENT ON COLUMN ecological_season.revision_count IS 'Revision count used for c COMMENT ON TABLE ecological_season IS 'Broad classification for the ecological season of a survey.' ; --- --- TABLE: intended_outcome +-- +-- TABLE: intended_outcome -- CREATE TABLE intended_outcome( @@ -91,8 +91,8 @@ COMMENT ON COLUMN intended_outcome.revision_count IS 'Revision count used for co COMMENT ON TABLE intended_outcome IS 'Broad classification of intended outcomes of the survey work.' ; --- --- TABLE: vantage +-- +-- TABLE: vantage -- CREATE TABLE vantage( @@ -155,17 +155,17 @@ COMMENT ON COLUMN survey.intended_outcome_id IS 'System generated surrogate prim COMMENT ON COLUMN survey.vantage_id IS 'System generated surrogate primary key identifier.' ; -ALTER TABLE survey ADD CONSTRAINT "Refecological_season212" +ALTER TABLE survey ADD CONSTRAINT "Refecological_season212" FOREIGN KEY (ecological_season_id) REFERENCES ecological_season(ecological_season_id) ; -ALTER TABLE survey ADD CONSTRAINT "Refvantage214" +ALTER TABLE survey ADD CONSTRAINT "Refvantage214" FOREIGN KEY (vantage_id) REFERENCES vantage(vantage_id) ; -ALTER TABLE survey ADD CONSTRAINT "Refintended_outcome211" +ALTER TABLE survey ADD CONSTRAINT "Refintended_outcome211" FOREIGN KEY (intended_outcome_id) REFERENCES intended_outcome(intended_outcome_id) ; @@ -198,11 +198,11 @@ ALTER TABLE survey ADD CONSTRAINT "Refvantage190" FOREIGN KEY (vantage_id) REFER ALTER TABLE survey ADD CONSTRAINT "Refecological_season190" FOREIGN KEY (ecological_season_id) REFERENCES ecological_season(ecological_season_id); ALTER TABLE survey ADD CONSTRAINT "Refintended_outcome190" FOREIGN KEY (intended_outcome_id) REFERENCES intended_outcome(intended_outcome_id); -alter table survey +alter table survey rename column objectives to additional_details ; -alter table survey +alter table survey alter column additional_details drop not null ; From 46ff3ab76e837556a160d6412f7e0814316684f9 Mon Sep 17 00:00:00 2001 From: Anissa Agahchen Date: Wed, 6 Apr 2022 14:56:44 -0700 Subject: [PATCH 08/66] view page rendering with codes mapping to values --- api/src/models/survey-view-update.ts | 2 ++ .../SurveyPurposeAndMethodology.tsx | 31 ++++++++++++++----- app/src/interfaces/useSurveyApi.interface.ts | 9 +++--- app/src/test-helpers/survey-helpers.ts | 9 +++--- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/api/src/models/survey-view-update.ts b/api/src/models/survey-view-update.ts index 5d4e7ed681..00b9b1d879 100644 --- a/api/src/models/survey-view-update.ts +++ b/api/src/models/survey-view-update.ts @@ -43,6 +43,7 @@ export class GetSurveyProprietorData { export class GetSurveyPurposeAndMethodologyData { id: number; intended_outcome_id: number; + field_method_id: number; additional_details: string; ecological_season_id: number; vantage_id: number; @@ -57,6 +58,7 @@ export class GetSurveyPurposeAndMethodologyData { this.id = data?.id ?? null; this.intended_outcome_id = data?.intended_outcome_id ?? null; + this.field_method_id = data?.field_method_id ?? null; this.additional_details = data?.additional_details ?? null; this.ecological_season_id = data?.ecological_season_id ?? null; this.vantage_id = data?.vantage_id ?? null; diff --git a/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx b/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx index 049ab15cbc..b8cfbd9e59 100644 --- a/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx +++ b/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx @@ -44,6 +44,7 @@ const SurveyPurposeAndMethodologyData: React.FC - {survey_purpose_and_methodology.intended_outcome} + {survey_purpose_and_methodology.intended_outcome_id && + codes?.intended_outcomes?.find( + (item: any) => item.id === survey_purpose_and_methodology.intended_outcome_id + )?.name} @@ -242,32 +248,41 @@ const SurveyPurposeAndMethodologyData: React.FC - {'put the additional comments in here'} + {survey_purpose_and_methodology.additional_details} Field Method + - {survey_purpose_and_methodology.field_method} + {survey_purpose_and_methodology.field_method_id && + codes?.field_methods?.find( + (item: any) => item.id === survey_purpose_and_methodology.field_method_id + )?.name} + - + Ecological Season - {survey_purpose_and_methodology.ecological_season} + {survey_purpose_and_methodology.ecological_season_id && + codes?.ecological_seasons?.find( + (item: any) => item.id === survey_purpose_and_methodology.ecological_season_id + )?.name} - - + Vantage Code - {survey_purpose_and_methodology.vantage_codes} + {survey_purpose_and_methodology.vantage_id && + codes?.vantage_codes?.find((item: any) => item.id === survey_purpose_and_methodology.vantage_id) + ?.name} diff --git a/app/src/interfaces/useSurveyApi.interface.ts b/app/src/interfaces/useSurveyApi.interface.ts index 6f1b8f9c3d..2fdeeba83b 100644 --- a/app/src/interfaces/useSurveyApi.interface.ts +++ b/app/src/interfaces/useSurveyApi.interface.ts @@ -72,10 +72,11 @@ export interface IGetSurveyForViewResponseDetails { export interface IGetSurveyForViewResponsePurposeAndMethodology { id: number; - intended_outcome: number; - field_method: number; - ecological_season: number; - vantage_codes: number[]; + intended_outcome_id: number; + additional_details: string; + field_method_id: number; + ecological_season_id: number; + vantage_id: number; } export interface IGetSurveyForViewResponseProprietor { diff --git a/app/src/test-helpers/survey-helpers.ts b/app/src/test-helpers/survey-helpers.ts index 207aab3d82..6ca3bfd988 100644 --- a/app/src/test-helpers/survey-helpers.ts +++ b/app/src/test-helpers/survey-helpers.ts @@ -49,10 +49,11 @@ export const getSurveyForViewResponse: IGetSurveyForViewResponse = { }, survey_purpose_and_methodology: { id: 1, - intended_outcome: 1, - field_method: 1, - ecological_season: 1, - vantage_codes: [1, 2] + intended_outcome_id: 1, + additional_details: 'details', + field_method_id: 1, + ecological_season_id: 1, + vantage_id: 1 }, survey_proprietor: { id: 23, From 71455ed2bc8fa68c92301301f852d1975c7b749c Mon Sep 17 00:00:00 2001 From: cgarrettjones Date: Wed, 6 Apr 2022 15:17:38 -0700 Subject: [PATCH 09/66] - addition of "survey vantage" table, intersect table for "survey" and "vantage" --- .../migrations/20220404093900_SIMS.1.1.0.ts | 702 +++++++++++------- .../smoke_tests/smoketest_release.1.1.0.sql | 10 +- 2 files changed, 424 insertions(+), 288 deletions(-) diff --git a/database/src/migrations/20220404093900_SIMS.1.1.0.ts b/database/src/migrations/20220404093900_SIMS.1.1.0.ts index 3660352394..68082b570a 100644 --- a/database/src/migrations/20220404093900_SIMS.1.1.0.ts +++ b/database/src/migrations/20220404093900_SIMS.1.1.0.ts @@ -9,290 +9,424 @@ import { Knex } from 'knex'; */ export async function up(knex: Knex): Promise { await knex.raw(` -set search_path = biohub, public; - -CREATE TABLE ecological_season( - ecological_season_id integer GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), - name varchar(50) NOT NULL, - record_effective_date date NOT NULL, - description varchar(3000), - record_end_date date, - create_date timestamptz(6) DEFAULT now() NOT NULL, - create_user integer NOT NULL, - update_date timestamptz(6), - update_user integer, - revision_count integer DEFAULT 0 NOT NULL, - CONSTRAINT ecological_season_pk PRIMARY KEY (ecological_season_id) -) -; - -COMMENT ON COLUMN ecological_season.ecological_season_id IS 'System generated surrogate primary key identifier.' -; -COMMENT ON COLUMN ecological_season.name IS 'The name of the project role.' -; -COMMENT ON COLUMN ecological_season.record_effective_date IS 'Record level effective date.' -; -COMMENT ON COLUMN ecological_season.description IS 'The description of the project type.' -; -COMMENT ON COLUMN ecological_season.record_end_date IS 'Record level end date.' -; -COMMENT ON COLUMN ecological_season.create_date IS 'The datetime the record was created.' -; -COMMENT ON COLUMN ecological_season.create_user IS 'The id of the user who created the record as identified in the system user table.' -; -COMMENT ON COLUMN ecological_season.update_date IS 'The datetime the record was updated.' -; -COMMENT ON COLUMN ecological_season.update_user IS 'The id of the user who updated the record as identified in the system user table.' -; -COMMENT ON COLUMN ecological_season.revision_count IS 'Revision count used for concurrency control.' -; -COMMENT ON TABLE ecological_season IS 'Broad classification for the ecological season of a survey.' -; - --- --- TABLE: intended_outcome --- - -CREATE TABLE intended_outcome( - intended_outcome_id integer GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), - name varchar(50) NOT NULL, - record_effective_date date NOT NULL, - description varchar(3000), - record_end_date date, - create_date timestamptz(6) DEFAULT now() NOT NULL, - create_user integer NOT NULL, - update_date timestamptz(6), - update_user integer, - revision_count integer DEFAULT 0 NOT NULL, - CONSTRAINT intended_outcome_pk PRIMARY KEY (intended_outcome_id) -) -; - -COMMENT ON COLUMN intended_outcome.intended_outcome_id IS 'System generated surrogate primary key identifier.' -; -COMMENT ON COLUMN intended_outcome.name IS 'The name of the project role.' -; -COMMENT ON COLUMN intended_outcome.record_effective_date IS 'Record level effective date.' -; -COMMENT ON COLUMN intended_outcome.description IS 'The description of the project type.' -; -COMMENT ON COLUMN intended_outcome.record_end_date IS 'Record level end date.' -; -COMMENT ON COLUMN intended_outcome.create_date IS 'The datetime the record was created.' -; -COMMENT ON COLUMN intended_outcome.create_user IS 'The id of the user who created the record as identified in the system user table.' -; -COMMENT ON COLUMN intended_outcome.update_date IS 'The datetime the record was updated.' -; -COMMENT ON COLUMN intended_outcome.update_user IS 'The id of the user who updated the record as identified in the system user table.' -; -COMMENT ON COLUMN intended_outcome.revision_count IS 'Revision count used for concurrency control.' -; -COMMENT ON TABLE intended_outcome IS 'Broad classification of intended outcomes of the survey work.' -; - --- --- TABLE: vantage --- - -CREATE TABLE vantage( - vantage_id integer GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), - name varchar(50) NOT NULL, - record_effective_date date NOT NULL, - description varchar(250), - record_end_date date, - create_date timestamptz(6) DEFAULT now() NOT NULL, - create_user integer NOT NULL, - update_date timestamptz(6), - update_user integer, - revision_count integer DEFAULT 0 NOT NULL, - CONSTRAINT vantage_pk PRIMARY KEY (vantage_id) -) -; - -COMMENT ON COLUMN vantage.vantage_id IS 'System generated surrogate primary key identifier.' -; -COMMENT ON COLUMN vantage.name IS 'The name of the project role.' -; -COMMENT ON COLUMN vantage.record_effective_date IS 'Record level effective date.' -; -COMMENT ON COLUMN vantage.description IS 'The description of the project type.' -; -COMMENT ON COLUMN vantage.record_end_date IS 'Record level end date.' -; -COMMENT ON COLUMN vantage.create_date IS 'The datetime the record was created.' -; -COMMENT ON COLUMN vantage.create_user IS 'The id of the user who created the record as identified in the system user table.' -; -COMMENT ON COLUMN vantage.update_date IS 'The datetime the record was updated.' -; -COMMENT ON COLUMN vantage.update_user IS 'The id of the user who updated the record as identified in the system user table.' -; -COMMENT ON COLUMN vantage.revision_count IS 'Revision count used for concurrency control.' -; -COMMENT ON TABLE vantage IS 'Broad classification for the vantage code of the survey.' -; - -CREATE UNIQUE INDEX ecological_season_nuk1 ON ecological_season(name, (record_end_date is NULL)) where record_end_date is null -; - -CREATE UNIQUE INDEX vantage_nuk1 ON vantage(name, (record_end_date is NULL)) where record_end_date is null -; - -CREATE UNIQUE INDEX intended_outcome_nuk1 ON intended_outcome(name, (record_end_date is NULL)) where record_end_date is null -; - -alter table survey -add column ecological_season_id integer, -add column intended_outcome_id integer, -add column vantage_id integer -; - -COMMENT ON COLUMN survey.ecological_season_id IS 'System generated surrogate primary key identifier.' -; -COMMENT ON COLUMN survey.intended_outcome_id IS 'System generated surrogate primary key identifier.' -; -COMMENT ON COLUMN survey.vantage_id IS 'System generated surrogate primary key identifier.' -; - -ALTER TABLE survey ADD CONSTRAINT "Refecological_season212" - FOREIGN KEY (ecological_season_id) - REFERENCES ecological_season(ecological_season_id) -; - -ALTER TABLE survey ADD CONSTRAINT "Refvantage214" - FOREIGN KEY (vantage_id) - REFERENCES vantage(vantage_id) -; - -ALTER TABLE survey ADD CONSTRAINT "Refintended_outcome211" - FOREIGN KEY (intended_outcome_id) - REFERENCES intended_outcome(intended_outcome_id) -; - -CREATE INDEX "Ref222214" ON survey(vantage_id) -; - -CREATE INDEX "Ref223211" ON survey(intended_outcome_id) -; - -CREATE INDEX "Ref220212" ON survey(ecological_season_id) -; - -alter table common_survey_methodology -rename to field_method -; - -alter table field_method -rename column common_survey_methodology_id to field_method_id -; - -alter table survey -rename column common_survey_methodology_id to field_method_id -; - -ALTER TABLE survey drop CONSTRAINT "Refcommon_survey_methodology190"; - -ALTER TABLE survey ADD CONSTRAINT "Reffield_method190" FOREIGN KEY (field_method_id) REFERENCES field_method(field_method_id); -ALTER TABLE survey ADD CONSTRAINT "Refvantage190" FOREIGN KEY (vantage_id) REFERENCES vantage(vantage_id); -ALTER TABLE survey ADD CONSTRAINT "Refecological_season190" FOREIGN KEY (ecological_season_id) REFERENCES ecological_season(ecological_season_id); -ALTER TABLE survey ADD CONSTRAINT "Refintended_outcome190" FOREIGN KEY (intended_outcome_id) REFERENCES intended_outcome(intended_outcome_id); - -alter table survey -rename column objectives to additional_details -; - -alter table survey -alter column additional_details drop not null -; - -alter trigger audit_common_survey_methodology on field_method rename to audit_field_method; -alter trigger journal_common_survey_methodology on field_method rename to journal_field_method; - -create trigger journal_intended_outcome after -insert or delete or update on biohub.intended_outcome for each row execute function biohub.tr_journal_trigger(); - -create trigger journal_ecological_season after -insert or delete or update on biohub.ecological_season for each row execute function biohub.tr_journal_trigger(); - -create trigger journal_vantage after -insert or delete or update on biohub.vantage for each row execute function biohub.tr_journal_trigger(); - -create trigger audit_intended_outcome before -insert or delete or update on biohub.intended_outcome for each row execute function biohub.tr_audit_trigger(); - -create trigger audit_ecological_season before -insert or delete or update on biohub.ecological_season for each row execute function biohub.tr_audit_trigger(); - -create trigger audit_vantage before -insert or delete or update on biohub.vantage for each row execute function biohub.tr_audit_trigger(); - -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Habitat Assessment', 'To assess habitat for its value to wildlife and to record evidence of its usage by wildlife.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Reconnaissance', 'To provide information for planning another Survey or to informally determine species presence.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Recruitment', 'To count or obtain an index of the number of new individuals (e.g., young) that have been added to the population between 2 points in time. For example, a caribou recruitment Survey counts young animals after winter; the young are considered established and contributing to the population.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Composition', 'To count or obtain an index of the number of individuals in a population belonging to particular age or sex categories. E.g., bull:cow ratio for moose.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Community Composition', 'To determine the numbers or proportions of species in an ecological community or geographic area. E.g., relative ground-cover by plant species, relative density of birds of each species in a forest.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Count', 'To obtain a number that indicates the number of individuals in an area. A population count may be obtained by enumerating every individual in a population (e.g., by doing a census) or by sampling a portion of the population (e.g., stratified random block design) and then adjusting the observed number to estimate the population size.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Count & Recruitment', 'To obtain a number that indicates the number of individuals in an area (population count) AND to count or obtain an index of the number of new individuals (e.g., young) that have been added to the population between 2 points in time (recruitment).'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Count & Composition', 'To obtain a number that indicates the number of individuals in an area (population count) AND to count or obtain an index of the number of individuals in a population belonging to particular age or sex categories (composition).'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Index', 'To obtain a population index. For example, to obtain a relative abundance index by calculating the number of tracks detected per kilometre of transect, or number of detections per hour of surveying.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Mortality', 'To count or obtain an index of the number and conditions of dead individuals, and/or the causes of death.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Survival', 'To count or obtain an index of the number of individuals in a population that have survived a period between 2 points in time.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Specimen Collection', 'To collect sample specimens of a species or taxon.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Translocation', 'To move individuals from one location to another.'); -insert into intended_outcome(record_effective_date, name, description) values (now(), 'Distribution or Range Map', 'To determine the manner in which a species (or population or taxon) is spatially arranged, or to define the geographic limits of the species.'); - -update field_method set description = 'A sampling technique in which a population is divided into discrete units called strata based on similar attributes. The researcher selects a small sample size with similar characteristics to represent a population group under study.' -where name = 'Stratified Random Block'; - -update field_method set record_end_date = now() -where name in ('Composition', 'Recruitment'); - -insert into field_method(record_effective_date, name, description) values (now(), 'Total Count', 'They are intended to enumerate all animals using 100% flight coverage of the study area. Alpine areas are usually small, and thus the technique is practical for surveying mountain sheep and goats, and sometimes caribou.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Encounter Transects', 'The recommended protocol for conducting herd composition surveys are encounter transects. Occasionally, however, sample blocks may be selected. The purpose of these surveys is to provide information on population composition and recruitment. Encounter transects can be flown by either fixed-wing aircraft or helicopter, and all visible animals are counted and classified. Encounter transects may follow predetermined straight lines, contours, or drainages. When classification is conducted, it will normally be necessary to deviate from the transect line to ensure accurate classification of the animals. Following the classification, the pilot should be instructed to resume the transect line. Ground transects are often secondary roads or trails.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Fixed-width Transects', 'When using fixed-width transects only animals within a defined survey area (strip) are counted. Fixed-widths can be defined by marks on the airplane struts, or by placing a board across the helicopter skids and calibrating that with a mark on the bubble window.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Wildlife Camera', 'To use a camera to record individuals or species in the absence of an observer.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Track Count', 'To count the number of tracks of a species or group of species.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Spotlight Count', 'To use a spotlight to see and identify or count the number of individuals.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Classification Transects/Blocks', 'The recommended protocol for conducting herd composition surveys are encounter transects. Occasionally, however, sample blocks may be selected. The purpose of these surveys is to provide information on population composition and recruitment.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Pellet/Scat Count', 'To count the number of pellet and/or scat groups of a species or group of species.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Call Playback', 'To play prerecorded calls of species and listen for responses.'); -insert into field_method(record_effective_date, name, description) values (now(), 'DNA - Individual', 'To obtain DNA samples from individuals.'); -insert into field_method(record_effective_date, name, description) values (now(), 'DNA - Environmental', 'To obtain environmental DNA.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture', 'To mark and subsequently resight or recapture individuals.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture - Wildlife Camera', 'To mark and subsequently resight or recapture individuals by use of a camera to record individuals or species in the absence of an observer.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture - Spotlight Count', 'To mark and subsequently resight or recapture individuals by use of a spotlight to see and identify or count the number of individuals.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture - DNA - Individual', 'To mark and subsequently resight or recapture individuals by obtaining DNA samples from individuals.'); -insert into field_method(record_effective_date, name, description) values (now(), 'Described in Comments', 'The field method is described in the comments field of the Survey. Note: Describing the data in comments rather than using a predefined code may reduce the clarity and accessibility of data.'); - -insert into ecological_season(record_effective_date, name, description) values (now(), 'Spring', ''); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Summer', ''); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Fall', ''); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Winter', ''); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Early Spring', ''); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Growing', 'The season of growth for a species; often includes all or portions of Spring, Summer, and Fall.'); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Early Winter', ''); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Mid Winter', ''); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Late Winter', ''); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Rutting', 'The courtship and copulation period of mammals, typically large mammals.'); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Breeding', 'The term "breeding season" typically applies to species, such as birds and some insects and some rodents, in which courtship and/or copulation is followed (within hours, days, or weeks) by hatching or birthing of young. In contrast, large mammals do not have a "breeding season" because they tend to have long gestation periods in which the birthing period is far removed from courtship and copulation.'); -insert into ecological_season(record_effective_date, name, description) values (now(), 'Post Birthing/Calving', 'The period after a species within a Study Area has finished giving birth to young, and the young are still closely associated with their parent(s) . For large mammals this period may start weeks after birthing, and extend for several weeks.'); - -insert into vantage(record_effective_date, name) values (now(), 'Aerial'); -insert into vantage(record_effective_date, name) values (now(), 'Walking'); -insert into vantage(record_effective_date, name) values (now(), 'Vehicle'); -insert into vantage(record_effective_date, name) values (now(), 'Boat'); - -set search_path = biohub_dapi_v1; - -create or replace view ecological_season as select * from biohub.ecological_season; -create or replace view vantage as select * from biohub.vantage; -create or replace view intended_outcome as select * from biohub.intended_outcome; -drop view survey; -create view survey as select * from biohub.survey; -drop view common_survey_methodology; -create view field_method as select * from biohub.field_method; -`); + set search_path = biohub, public; + + CREATE TABLE ecological_season( + ecological_season_id integer GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), + name varchar(50) NOT NULL, + record_effective_date date NOT NULL, + description varchar(3000), + record_end_date date, + create_date timestamptz(6) DEFAULT now() NOT NULL, + create_user integer NOT NULL, + update_date timestamptz(6), + update_user integer, + revision_count integer DEFAULT 0 NOT NULL, + CONSTRAINT ecological_season_pk PRIMARY KEY (ecological_season_id) + ) + ; + + + + COMMENT ON COLUMN ecological_season.ecological_season_id IS 'System generated surrogate primary key identifier.' + ; + COMMENT ON COLUMN ecological_season.name IS 'The name of the project role.' + ; + COMMENT ON COLUMN ecological_season.record_effective_date IS 'Record level effective date.' + ; + COMMENT ON COLUMN ecological_season.description IS 'The description of the project type.' + ; + COMMENT ON COLUMN ecological_season.record_end_date IS 'Record level end date.' + ; + COMMENT ON COLUMN ecological_season.create_date IS 'The datetime the record was created.' + ; + COMMENT ON COLUMN ecological_season.create_user IS 'The id of the user who created the record as identified in the system user table.' + ; + COMMENT ON COLUMN ecological_season.update_date IS 'The datetime the record was updated.' + ; + COMMENT ON COLUMN ecological_season.update_user IS 'The id of the user who updated the record as identified in the system user table.' + ; + COMMENT ON COLUMN ecological_season.revision_count IS 'Revision count used for concurrency control.' + ; + COMMENT ON TABLE ecological_season IS 'Broad classification for the ecological season of a survey.' + ; + + -- + -- TABLE: intended_outcome + -- + + CREATE TABLE intended_outcome( + intended_outcome_id integer GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), + name varchar(50) NOT NULL, + record_effective_date date NOT NULL, + description varchar(3000), + record_end_date date, + create_date timestamptz(6) DEFAULT now() NOT NULL, + create_user integer NOT NULL, + update_date timestamptz(6), + update_user integer, + revision_count integer DEFAULT 0 NOT NULL, + CONSTRAINT intended_outcome_pk PRIMARY KEY (intended_outcome_id) + ) + ; + + + + COMMENT ON COLUMN intended_outcome.intended_outcome_id IS 'System generated surrogate primary key identifier.' + ; + COMMENT ON COLUMN intended_outcome.name IS 'The name of the project role.' + ; + COMMENT ON COLUMN intended_outcome.record_effective_date IS 'Record level effective date.' + ; + COMMENT ON COLUMN intended_outcome.description IS 'The description of the project type.' + ; + COMMENT ON COLUMN intended_outcome.record_end_date IS 'Record level end date.' + ; + COMMENT ON COLUMN intended_outcome.create_date IS 'The datetime the record was created.' + ; + COMMENT ON COLUMN intended_outcome.create_user IS 'The id of the user who created the record as identified in the system user table.' + ; + COMMENT ON COLUMN intended_outcome.update_date IS 'The datetime the record was updated.' + ; + COMMENT ON COLUMN intended_outcome.update_user IS 'The id of the user who updated the record as identified in the system user table.' + ; + COMMENT ON COLUMN intended_outcome.revision_count IS 'Revision count used for concurrency control.' + ; + COMMENT ON TABLE intended_outcome IS 'Broad classification of intended outcomes of the survey work.' + ; + + -- + -- TABLE: vantage + -- + + CREATE TABLE vantage( + vantage_id integer GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), + name varchar(50) NOT NULL, + record_effective_date date NOT NULL, + description varchar(250), + record_end_date date, + create_date timestamptz(6) DEFAULT now() NOT NULL, + create_user integer NOT NULL, + update_date timestamptz(6), + update_user integer, + revision_count integer DEFAULT 0 NOT NULL, + CONSTRAINT vantage_pk PRIMARY KEY (vantage_id) + ) + ; + + + + COMMENT ON COLUMN vantage.vantage_id IS 'System generated surrogate primary key identifier.' + ; + COMMENT ON COLUMN vantage.name IS 'The name of the project role.' + ; + COMMENT ON COLUMN vantage.record_effective_date IS 'Record level effective date.' + ; + COMMENT ON COLUMN vantage.description IS 'The description of the project type.' + ; + COMMENT ON COLUMN vantage.record_end_date IS 'Record level end date.' + ; + COMMENT ON COLUMN vantage.create_date IS 'The datetime the record was created.' + ; + COMMENT ON COLUMN vantage.create_user IS 'The id of the user who created the record as identified in the system user table.' + ; + COMMENT ON COLUMN vantage.update_date IS 'The datetime the record was updated.' + ; + COMMENT ON COLUMN vantage.update_user IS 'The id of the user who updated the record as identified in the system user table.' + ; + COMMENT ON COLUMN vantage.revision_count IS 'Revision count used for concurrency control.' + ; + COMMENT ON TABLE vantage IS 'Broad classification for the vantage code of the survey.' + ; + + CREATE TABLE survey_vantage + ( + survey_vantage_id integer NOT NULL GENERATED ALWAYS AS IDENTITY + (START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + NO CYCLE), + survey_id integer NOT NULL, + vantage_id integer NOT NULL, + create_date timestamptz(6) NOT NULL DEFAULT now(), + create_user integer NOT NULL, + update_date timestamptz(6), + update_user integer, + revision_count integer NOT NULL DEFAULT 0, + CONSTRAINT survey_vantage_pk PRIMARY KEY (survey_vantage_id) + ) + WITH ( + OIDS=false + ); + + CREATE UNIQUE INDEX survey_vantage_uk1 ON survey_vantage + (survey_id, + vantage_id) + + ; + + CREATE INDEX "Ref153215" ON survey_vantage + (survey_id) + + ; + + CREATE INDEX "Ref222216" ON survey_vantage + (vantage_id) + + ; + + -- Add Referencing Foreign Keys SQL + + + ALTER TABLE survey_vantage + ADD + FOREIGN KEY (vantage_id) + REFERENCES vantage (vantage_id) + MATCH SIMPLE + ON DELETE NO ACTION + ON UPDATE NO ACTION + NOT VALID + ; + + ALTER TABLE survey_vantage + ADD + FOREIGN KEY (survey_id) + REFERENCES survey (survey_id) + MATCH SIMPLE + ON DELETE NO ACTION + ON UPDATE NO ACTION + NOT VALID + ; + + COMMENT ON TABLE survey_vantage IS 'An associative entity that joins surveys and vantage codes.'; + + COMMENT ON COLUMN survey_vantage.survey_vantage_id IS 'System generated surrogate primary key identifier.'; + + COMMENT ON COLUMN survey_vantage.survey_id IS 'System generated surrogate primary key identifier.'; + + COMMENT ON COLUMN survey_vantage.vantage_id IS 'System generated surrogate primary key identifier.'; + + COMMENT ON COLUMN survey_vantage.create_date IS 'The datetime the record was created.'; + + COMMENT ON COLUMN survey_vantage.create_user IS 'The id of the user who created the record as identified in the system user table.'; + + COMMENT ON COLUMN survey_vantage.update_date IS 'The datetime the record was updated.'; + + COMMENT ON COLUMN survey_vantage.update_user IS 'The id of the user who updated the record as identified in the system user table.'; + + COMMENT ON COLUMN survey_vantage.revision_count IS 'Revision count used for concurrency control.'; + + + CREATE UNIQUE INDEX ecological_season_nuk1 ON ecological_season(name, (record_end_date is NULL)) where record_end_date is null + ; + + CREATE UNIQUE INDEX vantage_nuk1 ON vantage(name, (record_end_date is NULL)) where record_end_date is null + ; + + CREATE UNIQUE INDEX intended_outcome_nuk1 ON intended_outcome(name, (record_end_date is NULL)) where record_end_date is null + ; + + alter table survey + add column ecological_season_id integer, + add column intended_outcome_id integer + ; + + COMMENT ON COLUMN survey.ecological_season_id IS 'System generated surrogate primary key identifier.' + ; + COMMENT ON COLUMN survey.intended_outcome_id IS 'System generated surrogate primary key identifier.' + ; + + ALTER TABLE survey ADD CONSTRAINT "Refecological_season212" + FOREIGN KEY (ecological_season_id) + REFERENCES ecological_season(ecological_season_id) + ; + + ALTER TABLE survey ADD CONSTRAINT "Refintended_outcome211" + FOREIGN KEY (intended_outcome_id) + REFERENCES intended_outcome(intended_outcome_id) + ; + + CREATE INDEX "Ref223211" ON survey(intended_outcome_id) + ; + + CREATE INDEX "Ref220212" ON survey(ecological_season_id) + ; + + alter table common_survey_methodology + rename to field_method + ; + + alter table field_method + rename column common_survey_methodology_id to field_method_id + ; + + alter table survey + rename column common_survey_methodology_id to field_method_id + ; + + ALTER TABLE survey drop CONSTRAINT "Refcommon_survey_methodology190"; + + ALTER TABLE survey ADD CONSTRAINT "Reffield_method190" FOREIGN KEY (field_method_id) REFERENCES field_method(field_method_id); + ALTER TABLE survey ADD CONSTRAINT "Refecological_season190" FOREIGN KEY (ecological_season_id) REFERENCES ecological_season(ecological_season_id); + ALTER TABLE survey ADD CONSTRAINT "Refintended_outcome190" FOREIGN KEY (intended_outcome_id) REFERENCES intended_outcome(intended_outcome_id); + + alter table survey + rename column objectives to additional_details + ; + + alter table survey + alter column additional_details drop not null + ; + + alter trigger audit_common_survey_methodology on field_method rename to audit_field_method; + alter trigger journal_common_survey_methodology on field_method rename to journal_field_method; + + create trigger journal_intended_outcome after + insert or delete or update on biohub.intended_outcome for each row execute function biohub.tr_journal_trigger(); + + create trigger journal_ecological_season after + insert or delete or update on biohub.ecological_season for each row execute function biohub.tr_journal_trigger(); + + create trigger journal_vantage after + insert or delete or update on biohub.vantage for each row execute function biohub.tr_journal_trigger(); + + create trigger journal_survey_vantage after + insert or delete or update on biohub.survey_vantage for each row execute function biohub.tr_journal_trigger(); + + create trigger audit_intended_outcome before + insert or delete or update on biohub.intended_outcome for each row execute function biohub.tr_audit_trigger(); + + create trigger audit_ecological_season before + insert or delete or update on biohub.ecological_season for each row execute function biohub.tr_audit_trigger(); + + create trigger audit_vantage before + insert or delete or update on biohub.vantage for each row execute function biohub.tr_audit_trigger(); + + create trigger audit_survey_vantage before + insert or delete or update on biohub.survey_vantage for each row execute function biohub.tr_audit_trigger(); + + -- api_delete_survey.sql + drop procedure if exists api_delete_survey; + + create or replace procedure api_delete_survey(p_survey_id survey.survey_id%type) + language plpgsql + security definer + as + $$ + -- ******************************************************************* + -- Procedure: api_delete_survey + -- Purpose: deletes a survey and dependencies + -- + -- MODIFICATION HISTORY + -- Person Date Comments + -- ---------------- ----------- -------------------------------------- + -- shreyas.devalapurkar@quartech.com + -- 2021-06-18 initial release + -- charlie.garrettjones@quartech.com + -- 2021-06-21 added occurrence submission delete + -- charlie.garrettjones@quartech.com + -- 2021-09-21 added survey summary submission delete + -- charlie.garrettjones@quartech.com + -- 2022-04-06 added survey_vantage + -- ******************************************************************* + declare + _occurrence_submission_id occurrence_submission.occurrence_submission_id%type; + begin + for _occurrence_submission_id in (select occurrence_submission_id from occurrence_submission where survey_id = p_survey_id) loop + call api_delete_occurrence_submission(_occurrence_submission_id); + end loop; + + delete from survey_vantage where survey_id = p_survey_id; + delete from survey_summary_submission_message where survey_summary_submission_id in (select survey_summary_submission_id from survey_summary_submission where survey_id = p_survey_id); + delete from survey_summary_detail where survey_summary_submission_id in (select survey_summary_submission_id from survey_summary_submission where survey_id = p_survey_id); + delete from survey_summary_submission where survey_id = p_survey_id; + delete from survey_proprietor where survey_id = p_survey_id; + delete from survey_attachment where survey_id = p_survey_id; + delete from survey_report_author where survey_report_attachment_id in (select survey_report_attachment_id from survey_report_attachment where survey_id = p_survey_id); + delete from survey_report_attachment where survey_id = p_survey_id; + delete from study_species where survey_id = p_survey_id; + delete from survey_funding_source where survey_id = p_survey_id; + + update permit set survey_id = null where survey_id = p_survey_id; + + exception + when others THEN + raise; + end; + $$; + + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Habitat Assessment', 'To assess habitat for its value to wildlife and to record evidence of its usage by wildlife.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Reconnaissance', 'To provide information for planning another Survey or to informally determine species presence.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Recruitment', 'To count or obtain an index of the number of new individuals (e.g., young) that have been added to the population between 2 points in time. For example, a caribou recruitment Survey counts young animals after winter; the young are considered established and contributing to the population.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Composition', 'To count or obtain an index of the number of individuals in a population belonging to particular age or sex categories. E.g., bull:cow ratio for moose.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Community Composition', 'To determine the numbers or proportions of species in an ecological community or geographic area. E.g., relative ground-cover by plant species, relative density of birds of each species in a forest.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Count', 'To obtain a number that indicates the number of individuals in an area. A population count may be obtained by enumerating every individual in a population (e.g., by doing a census) or by sampling a portion of the population (e.g., stratified random block design) and then adjusting the observed number to estimate the population size.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Count & Recruitment', 'To obtain a number that indicates the number of individuals in an area (population count) AND to count or obtain an index of the number of new individuals (e.g., young) that have been added to the population between 2 points in time (recruitment).'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Count & Composition', 'To obtain a number that indicates the number of individuals in an area (population count) AND to count or obtain an index of the number of individuals in a population belonging to particular age or sex categories (composition).'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Population Index', 'To obtain a population index. For example, to obtain a relative abundance index by calculating the number of tracks detected per kilometre of transect, or number of detections per hour of surveying.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Mortality', 'To count or obtain an index of the number and conditions of dead individuals, and/or the causes of death.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Survival', 'To count or obtain an index of the number of individuals in a population that have survived a period between 2 points in time.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Specimen Collection', 'To collect sample specimens of a species or taxon.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Translocation', 'To move individuals from one location to another.'); + insert into intended_outcome(record_effective_date, name, description) values (now(), 'Distribution or Range Map', 'To determine the manner in which a species (or population or taxon) is spatially arranged, or to define the geographic limits of the species.'); + + update field_method set description = 'A sampling technique in which a population is divided into discrete units called strata based on similar attributes. The researcher selects a small sample size with similar characteristics to represent a population group under study.' + where name = 'Stratified Random Block'; + + update field_method set record_end_date = now() + where name in ('Composition', 'Recruitment'); + + insert into field_method(record_effective_date, name, description) values (now(), 'Total Count', 'They are intended to enumerate all animals using 100% flight coverage of the study area. Alpine areas are usually small, and thus the technique is practical for surveying mountain sheep and goats, and sometimes caribou.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Encounter Transects', 'The recommended protocol for conducting herd composition surveys are encounter transects. Occasionally, however, sample blocks may be selected. The purpose of these surveys is to provide information on population composition and recruitment. Encounter transects can be flown by either fixed-wing aircraft or helicopter, and all visible animals are counted and classified. Encounter transects may follow predetermined straight lines, contours, or drainages. When classification is conducted, it will normally be necessary to deviate from the transect line to ensure accurate classification of the animals. Following the classification, the pilot should be instructed to resume the transect line. Ground transects are often secondary roads or trails.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Fixed-width Transects', 'When using fixed-width transects only animals within a defined survey area (strip) are counted. Fixed-widths can be defined by marks on the airplane struts, or by placing a board across the helicopter skids and calibrating that with a mark on the bubble window.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Wildlife Camera', 'To use a camera to record individuals or species in the absence of an observer.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Track Count', 'To count the number of tracks of a species or group of species.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Spotlight Count', 'To use a spotlight to see and identify or count the number of individuals.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Classification Transects/Blocks', 'The recommended protocol for conducting herd composition surveys are encounter transects. Occasionally, however, sample blocks may be selected. The purpose of these surveys is to provide information on population composition and recruitment.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Pellet/Scat Count', 'To count the number of pellet and/or scat groups of a species or group of species.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Call Playback', 'To play prerecorded calls of species and listen for responses.'); + insert into field_method(record_effective_date, name, description) values (now(), 'DNA - Individual', 'To obtain DNA samples from individuals.'); + insert into field_method(record_effective_date, name, description) values (now(), 'DNA - Environmental', 'To obtain environmental DNA.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture', 'To mark and subsequently resight or recapture individuals.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture - Wildlife Camera', 'To mark and subsequently resight or recapture individuals by use of a camera to record individuals or species in the absence of an observer.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture - Spotlight Count', 'To mark and subsequently resight or recapture individuals by use of a spotlight to see and identify or count the number of individuals.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Mark Resight Recapture - DNA - Individual', 'To mark and subsequently resight or recapture individuals by obtaining DNA samples from individuals.'); + insert into field_method(record_effective_date, name, description) values (now(), 'Described in Comments', 'The field method is described in the comments field of the Survey. Note: Describing the data in comments rather than using a predefined code may reduce the clarity and accessibility of data.'); + + insert into ecological_season(record_effective_date, name, description) values (now(), 'Spring', ''); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Summer', ''); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Fall', ''); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Winter', ''); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Early Spring', ''); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Growing', 'The season of growth for a species; often includes all or portions of Spring, Summer, and Fall.'); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Early Winter', ''); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Mid Winter', ''); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Late Winter', ''); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Rutting', 'The courtship and copulation period of mammals, typically large mammals.'); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Breeding', 'The term "breeding season" typically applies to species, such as birds and some insects and some rodents, in which courtship and/or copulation is followed (within hours, days, or weeks) by hatching or birthing of young. In contrast, large mammals do not have a "breeding season" because they tend to have long gestation periods in which the birthing period is far removed from courtship and copulation.'); + insert into ecological_season(record_effective_date, name, description) values (now(), 'Post Birthing/Calving', 'The period after a species within a Study Area has finished giving birth to young, and the young are still closely associated with their parent(s) . For large mammals this period may start weeks after birthing, and extend for several weeks.'); + + insert into vantage(record_effective_date, name) values (now(), 'Vantage Code'); + insert into vantage(record_effective_date, name) values (now(), 'Aerial'); + insert into vantage(record_effective_date, name) values (now(), 'Walking'); + insert into vantage(record_effective_date, name) values (now(), 'Vehicle'); + insert into vantage(record_effective_date, name) values (now(), 'Boat'); + + set search_path = biohub_dapi_v1; + + create view ecological_season as select * from biohub.ecological_season; + create view intended_outcome as select * from biohub.intended_outcome; + create view vantage as select * from biohub.vantage; + create view survey_vantage as select * from biohub.survey_vantage; + + drop view survey; + create view survey as select * from biohub.survey; + drop view common_survey_methodology; + create view field_method as select * from biohub.field_method; + drop view template_methodology_species; + create view template_methodology_species as select * from biohub.template_methodology_species; + `); } export async function down(knex: Knex): Promise { diff --git a/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql b/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql index d6d7e4ccb7..f671ce52fe 100644 --- a/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql +++ b/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql @@ -131,8 +131,7 @@ begin , lead_last_name , geography , ecological_season_id - , intended_outcome_id - , vantage_id) + , intended_outcome_id) values (_project_id , 'survey name' , 'survey objectives' @@ -143,8 +142,8 @@ begin , 'lead last' , _geography , (select ecological_season_id from ecological_season where name = 'Growing') - , (select intended_outcome_id from intended_outcome where name = 'Survival') - , (select vantage_id from vantage where name = 'Aerial')) returning survey_id into _survey_id; + , (select intended_outcome_id from intended_outcome where name = 'Survival') + ) returning survey_id into _survey_id; insert into survey_proprietor (survey_id, first_nations_id, proprietor_type_id, rationale,disa_required) values (_survey_id, (select first_nations_id from first_nations where name = 'Squamish Nation'), (select proprietor_type_id from proprietor_type where name = 'First Nations Land'), 'proprietor rationale', true); @@ -154,6 +153,7 @@ begin insert into survey_report_author (survey_report_attachment_id, first_name, last_name) values (_survey_report_attachment_id, 'bob', 'dole'); insert into study_species (survey_id, wldtaxonomic_units_id, is_focal) values (_survey_id, (select wldtaxonomic_units_id from wldtaxonomic_units where CODE = 'AMARALB'), true); insert into survey_funding_source (survey_id, project_funding_source_id) values (_survey_id, _project_funding_source_id); + insert into survey_vantage(survey_id, vantage_id) values (_survey_id, (select vantage_id from vantage where name = 'Aerial')); select count(1) into _count from survey; assert _count = 1, 'FAIL survey'; @@ -169,6 +169,8 @@ begin assert _count = 1, 'FAIL study_species'; select count(1) into _count from survey_funding_source; assert _count = 1, 'FAIL survey_funding_source'; + select count(1) into _count from survey_vantage; + assert _count = 1, 'FAIL survey_vantage'; -- occurrence -- occurrence submission 1 From 6dac84ea5ade2b0e3741daae3ea207c909fad036 Mon Sep 17 00:00:00 2001 From: cgarrettjones Date: Wed, 6 Apr 2022 15:29:58 -0700 Subject: [PATCH 10/66] - remove incorrect vantage code from lookup --- database/src/migrations/20220404093900_SIMS.1.1.0.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/database/src/migrations/20220404093900_SIMS.1.1.0.ts b/database/src/migrations/20220404093900_SIMS.1.1.0.ts index 68082b570a..5388a0dea1 100644 --- a/database/src/migrations/20220404093900_SIMS.1.1.0.ts +++ b/database/src/migrations/20220404093900_SIMS.1.1.0.ts @@ -407,7 +407,6 @@ export async function up(knex: Knex): Promise { insert into ecological_season(record_effective_date, name, description) values (now(), 'Breeding', 'The term "breeding season" typically applies to species, such as birds and some insects and some rodents, in which courtship and/or copulation is followed (within hours, days, or weeks) by hatching or birthing of young. In contrast, large mammals do not have a "breeding season" because they tend to have long gestation periods in which the birthing period is far removed from courtship and copulation.'); insert into ecological_season(record_effective_date, name, description) values (now(), 'Post Birthing/Calving', 'The period after a species within a Study Area has finished giving birth to young, and the young are still closely associated with their parent(s) . For large mammals this period may start weeks after birthing, and extend for several weeks.'); - insert into vantage(record_effective_date, name) values (now(), 'Vantage Code'); insert into vantage(record_effective_date, name) values (now(), 'Aerial'); insert into vantage(record_effective_date, name) values (now(), 'Walking'); insert into vantage(record_effective_date, name) values (now(), 'Vehicle'); @@ -426,7 +425,7 @@ export async function up(knex: Knex): Promise { create view field_method as select * from biohub.field_method; drop view template_methodology_species; create view template_methodology_species as select * from biohub.template_methodology_species; - `); + `); } export async function down(knex: Knex): Promise { From d3b9d6c8c62c76b80d3243a6421223a89531907a Mon Sep 17 00:00:00 2001 From: Anissa Agahchen Date: Thu, 7 Apr 2022 10:51:24 -0700 Subject: [PATCH 11/66] Create and View page updated with multiple vantage points --- api/src/models/survey-create.ts | 5 +- api/src/models/survey-view-update.ts | 37 +++++++------ api/src/openapi/schemas/survey.ts | 10 ++-- .../project/{projectId}/survey/create.ts | 2 +- .../{projectId}/survey/{surveyId}/view.ts | 4 +- .../queries/survey/survey-create-queries.ts | 2 +- api/src/queries/survey/survey-view-queries.ts | 2 - .../survey/survey-view-update-queries.ts | 45 +++++++++++++++- .../components/PurposeAndMethodologyForm.tsx | 43 +++------------ .../features/surveys/view/SurveyDetails.tsx | 2 - .../SurveyPurposeAndMethodology.tsx | 53 +++++-------------- app/src/hooks/api/useSurveyApi.ts | 2 - app/src/interfaces/useSurveyApi.interface.ts | 4 +- app/src/test-helpers/survey-helpers.ts | 2 +- 14 files changed, 98 insertions(+), 115 deletions(-) diff --git a/api/src/models/survey-create.ts b/api/src/models/survey-create.ts index caead0ad62..5638a4d80d 100644 --- a/api/src/models/survey-create.ts +++ b/api/src/models/survey-create.ts @@ -19,8 +19,7 @@ export class PostSurveyObject { ancillary_species: number[]; field_method_id: number; ecological_season_id: number; - // vantage_codes: number[]; - vantage_id: number; + vantage_code_ids: number[]; start_date: string; end_date: string; survey_area_name: string; @@ -63,7 +62,7 @@ export class PostSurveyObject { this.intended_outcome_id = obj?.intended_outcome_id || null; this.ecological_season_id = obj?.ecological_season_id || null; this.additional_details = obj?.additional_details || null; - this.vantage_id = obj?.vantage_id || null; + this.vantage_code_ids = (obj?.vantage_code_ids?.length && obj.vantage_code_ids) || []; this.geometry = (obj?.geometry?.length && obj.geometry) || []; this.survey_proprietor = (obj && obj.survey_data_proprietary === 'true' && new PostSurveyProprietorData(obj)) || undefined; diff --git a/api/src/models/survey-view-update.ts b/api/src/models/survey-view-update.ts index 00b9b1d879..1710a66e54 100644 --- a/api/src/models/survey-view-update.ts +++ b/api/src/models/survey-view-update.ts @@ -41,27 +41,30 @@ export class GetSurveyProprietorData { } export class GetSurveyPurposeAndMethodologyData { - id: number; - intended_outcome_id: number; - field_method_id: number; - additional_details: string; - ecological_season_id: number; - vantage_id: number; - revision_count: number; - - constructor(data?: any) { + constructor(responseData?: any) { defaultLog.debug({ label: 'GetSurveyPurposeAndMethodologyData', message: 'params', - surveyProprietorData: data + data: responseData }); - this.id = data?.id ?? null; - this.intended_outcome_id = data?.intended_outcome_id ?? null; - this.field_method_id = data?.field_method_id ?? null; - this.additional_details = data?.additional_details ?? null; - this.ecological_season_id = data?.ecological_season_id ?? null; - this.vantage_id = data?.vantage_id ?? null; - this.revision_count = data?.revision_count ?? null; + const obj = {}; + + responseData.forEach((item: any) => { + if (!obj[item.id]) { + obj[item.id] = { + id: item.id, + intended_outcome_id: item.intended_outcome_id, + additional_details: item.additional_details, + field_method_id: item.field_method_id, + ecological_season_id: item.ecological_season_id, + revision_count: item.revision_count, + vantage_code_ids: [item.vantage_id] + }; + } else { + obj[item.id].vantage_code_ids.push(item.vantage_id); + } + }); + return Object.values(obj); } } diff --git a/api/src/openapi/schemas/survey.ts b/api/src/openapi/schemas/survey.ts index 934a86eee3..61f346f9b2 100644 --- a/api/src/openapi/schemas/survey.ts +++ b/api/src/openapi/schemas/survey.ts @@ -13,7 +13,7 @@ export const surveyCreatePostRequestObject = { 'intended_outcome_id', 'additional_details', 'field_method_id', - 'vantage_id', + 'vantage_code_ids', 'ecological_season_id', 'biologist_first_name', 'biologist_last_name', @@ -46,7 +46,6 @@ export const surveyCreatePostRequestObject = { }, description: 'Selected ancillary species ids' }, - intended_outcome_id: { type: 'number' }, @@ -56,8 +55,11 @@ export const surveyCreatePostRequestObject = { field_method_id: { type: 'number' }, - vantage_id: { - type: 'number' + vantage_code_ids: { + type: 'array', + items: { + type: 'number' + } }, ecological_season_id: { type: 'number' diff --git a/api/src/paths/project/{projectId}/survey/create.ts b/api/src/paths/project/{projectId}/survey/create.ts index 5963b6973f..a9e9f82a86 100644 --- a/api/src/paths/project/{projectId}/survey/create.ts +++ b/api/src/paths/project/{projectId}/survey/create.ts @@ -172,7 +172,7 @@ export function createSurvey(): RequestHandler { //Handle vantage codes associated to this survey promises.push( Promise.all( - sanitizedPostSurveyData.vantage_codes.map((vantageCode: number) => + sanitizedPostSurveyData.vantage_code_ids.map((vantageCode: number) => insertVantageCodes(vantageCode, surveyId, connection) ) ) diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts index 62a88aa5a9..7eb12d20a6 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts @@ -123,7 +123,7 @@ export function getSurveyForView(): RequestHandler { }); const getSurveyPurposeAndMethodology = - (surveyPurposeAndMethodology && new GetSurveyPurposeAndMethodologyData(surveyPurposeAndMethodology)) || null; + (surveyPurposeAndMethodology && new GetSurveyPurposeAndMethodologyData(surveyPurposeAndMethodology))[0] || null; const getSurveyProprietorData = (surveyProprietorData && new GetSurveyProprietorData(surveyProprietorData)) || null; @@ -176,7 +176,7 @@ export const getSurveyPurposeAndMethodologyDataForView = async ( throw new HTTP400('Failed to get survey purpose and methodology data'); } - return (response && response.rows?.[0]) || null; + return (response && response.rows) || []; }; export const getSurveyFundingSourcesDataForView = async ( diff --git a/api/src/queries/survey/survey-create-queries.ts b/api/src/queries/survey/survey-create-queries.ts index e17e52eef9..5a03260845 100644 --- a/api/src/queries/survey/survey-create-queries.ts +++ b/api/src/queries/survey/survey-create-queries.ts @@ -319,7 +319,7 @@ export const postAncillarySpeciesSQL = (speciesId: number, surveyId: number): SQ * @param {number} surveyId * @returns {SQLStatement} sql query object */ - export const postVantageCodesSQL = (vantageCodeId: number, surveyId: number): SQLStatement | null => { +export const postVantageCodesSQL = (vantageCodeId: number, surveyId: number): SQLStatement | null => { defaultLog.debug({ label: 'postVantageCodesSQL', message: 'params', vantageCodeId, surveyId }); if (!vantageCodeId || !surveyId) { diff --git a/api/src/queries/survey/survey-view-queries.ts b/api/src/queries/survey/survey-view-queries.ts index 64d9596c04..0ba1b15309 100644 --- a/api/src/queries/survey/survey-view-queries.ts +++ b/api/src/queries/survey/survey-view-queries.ts @@ -149,7 +149,6 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n s.field_method_id, s.ecological_season_id, s.intended_outcome_id, - s.vantage_id, s.start_date, s.end_date, s.lead_first_name, @@ -189,7 +188,6 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n s.additional_details, s.intended_outcome_id, s.ecological_season_id, - s.vantage_id, s.start_date, s.end_date, s.lead_first_name, diff --git a/api/src/queries/survey/survey-view-update-queries.ts b/api/src/queries/survey/survey-view-update-queries.ts index 8e7cd497b5..36276e1a92 100644 --- a/api/src/queries/survey/survey-view-update-queries.ts +++ b/api/src/queries/survey/survey-view-update-queries.ts @@ -183,11 +183,16 @@ export const getSurveyPurposeAndMethodologyForUpdateSQL = (surveyId: number): SQ s.additional_details, s.ecological_season_id, s.intended_outcome_id, - s.vantage_id + s.revision_count, + sv.vantage_id FROM survey s + LEFT OUTER JOIN + survey_vantage sv + ON + sv.survey_id = s.survey_id WHERE - survey_id = ${surveyId}; + s.survey_id = ${surveyId}; `; defaultLog.debug({ @@ -199,3 +204,39 @@ export const getSurveyPurposeAndMethodologyForUpdateSQL = (surveyId: number): SQ return sqlStatement; }; + +/** + * SQL query to retrieve a survey_proprietor row. + * + * @param {number} surveyId + * @returns {SQLStatement} sql query object + */ +export const getSurveyVantageCodesSQL = (surveyId: number): SQLStatement | null => { + defaultLog.debug({ + label: 'getSurveyVantageCodesSQL', + message: 'params', + surveyId + }); + + if (!surveyId) { + return null; + } + + const sqlStatement = SQL` + SELECT + vantage_id + FROM + survey_vantage + WHERE + survey_id = ${surveyId}; + `; + + defaultLog.debug({ + label: 'getSurveyVantageCodesSQL', + message: 'sql', + 'sqlStatement.text': sqlStatement.text, + 'sqlStatement.values': sqlStatement.values + }); + + return sqlStatement; +}; diff --git a/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx b/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx index 2340fa9125..843ee593a5 100644 --- a/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx +++ b/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx @@ -11,7 +11,7 @@ import { IAutocompleteFieldOption } from 'components/fields/AutocompleteField'; import CustomTextField from 'components/fields/CustomTextField'; //import MultiAutocompleteFieldVariableSize from 'components/fields/MultiAutocompleteFieldVariableSize'; //import { IMultiAutocompleteFieldOption } from 'components/fields/MultiAutocompleteField'; -//import MultiAutocompleteFieldVariableSize from 'components/fields/MultiAutocompleteFieldVariableSize'; +import MultiAutocompleteFieldVariableSize from 'components/fields/MultiAutocompleteFieldVariableSize'; import { useFormikContext } from 'formik'; import React from 'react'; import yup from 'utils/YupSchema'; @@ -21,7 +21,7 @@ export interface IPurposeAndMethodologyForm { additional_details: string; field_method_id: number; ecological_season_id: number; - vantage_id: number; + vantage_code_ids: number[]; } export const PurposeAndMethodologyInitialValues: IPurposeAndMethodologyForm = { @@ -29,7 +29,7 @@ export const PurposeAndMethodologyInitialValues: IPurposeAndMethodologyForm = { additional_details: '', field_method_id: ('' as unknown) as number, ecological_season_id: ('' as unknown) as number, - vantage_id: ('' as unknown) as number + vantage_code_ids: [] }; export const PurposeAndMethodologyYupSchema = yup.object().shape({ @@ -37,7 +37,7 @@ export const PurposeAndMethodologyYupSchema = yup.object().shape({ additional_details: yup.string(), intended_outcome_id: yup.number().required('You must provide intended outcomes for the survey'), ecological_season_id: yup.number().required('You must provide an ecological season for the survey'), - vantage_id: yup.number().required('You must provide a vantage code for the survey') + vantage_code_ids: yup.array().min(1, 'You must specify a focal species').required('Required') }); export interface IPurposeAndMethodologyFormProps { @@ -93,7 +93,6 @@ const PurposeAndMethologyForm: React.FC = (prop other={{ multiline: true, required: true, rows: 2 }} /> - Survey Methodology @@ -120,7 +119,6 @@ const PurposeAndMethologyForm: React.FC = (prop {formikProps.touched.field_method_id && formikProps.errors.field_method_id} - Survey Methodology @@ -149,41 +147,14 @@ const PurposeAndMethologyForm: React.FC = (prop - - - - Vantage Code - - {formikProps.touched.vantage_id && formikProps.errors.vantage_id} - - - - {/* -TODO://bring this back once we can do a multi-select - and have the database table to support it - */} + ); diff --git a/app/src/features/surveys/view/SurveyDetails.tsx b/app/src/features/surveys/view/SurveyDetails.tsx index d07f940fe5..311d6538f1 100644 --- a/app/src/features/surveys/view/SurveyDetails.tsx +++ b/app/src/features/surveys/view/SurveyDetails.tsx @@ -24,8 +24,6 @@ export interface ISurveyDetailsProps { const SurveyDetails: React.FC = (props) => { const { surveyForViewData, codes, refresh, projectForViewData } = props; - console.log('survey for view data in the SurveyDetails', surveyForViewData); - return ( <> diff --git a/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx b/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx index b8cfbd9e59..b42d841e4e 100644 --- a/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx +++ b/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx @@ -48,8 +48,6 @@ const SurveyPurposeAndMethodologyData: React.FC({ dialogTitle: EditSurveyPurposeAndMethodologyI18N.editErrorTitle, dialogText: EditSurveyPurposeAndMethodologyI18N.editErrorText, @@ -115,8 +89,6 @@ const SurveyPurposeAndMethodologyData: React.FC { + codes?.intended_outcomes?.map((item) => { return { value: item.id, label: item.name }; }) || [] } field_methods={ - field_methods.map((item) => { + codes?.field_methods?.map((item) => { return { value: item.id, label: item.name }; }) || [] } ecological_seasons={ - ecological_seasons.map((item) => { + codes?.ecological_seasons?.map((item) => { return { value: item.id, label: item.name }; }) || [] } vantage_codes={ - vantage_codes.map((item) => { + codes?.vantage_codes?.map((item) => { return { value: item.id, label: item.name }; }) || [] } @@ -279,11 +250,13 @@ const SurveyPurposeAndMethodologyData: React.FC Vantage Code - - {survey_purpose_and_methodology.vantage_id && - codes?.vantage_codes?.find((item: any) => item.id === survey_purpose_and_methodology.vantage_id) - ?.name} - + {survey_purpose_and_methodology.vantage_code_ids?.map((vc_id: number, index: number) => { + return ( + + {codes?.vantage_codes?.find((item: any) => item.id === vc_id)?.name} + + ); + })} )} diff --git a/app/src/hooks/api/useSurveyApi.ts b/app/src/hooks/api/useSurveyApi.ts index bbd4ed43a6..10dd06be0f 100644 --- a/app/src/hooks/api/useSurveyApi.ts +++ b/app/src/hooks/api/useSurveyApi.ts @@ -47,8 +47,6 @@ const useSurveyApi = (axios: AxiosInstance) => { const getSurveyForView = async (projectId: number, surveyId: number): Promise => { const { data } = await axios.get(`/api/project/${projectId}/survey/${surveyId}/view`); - console.log('survey for view: ', data); - return data; }; diff --git a/app/src/interfaces/useSurveyApi.interface.ts b/app/src/interfaces/useSurveyApi.interface.ts index 2fdeeba83b..8a4899c4cb 100644 --- a/app/src/interfaces/useSurveyApi.interface.ts +++ b/app/src/interfaces/useSurveyApi.interface.ts @@ -76,7 +76,7 @@ export interface IGetSurveyForViewResponsePurposeAndMethodology { additional_details: string; field_method_id: number; ecological_season_id: number; - vantage_id: number; + vantage_code_ids: number[]; } export interface IGetSurveyForViewResponseProprietor { @@ -111,7 +111,7 @@ export interface IGetSurveyForUpdateResponsePurposeAndMethodology { additional_details: string; field_method_id: number; ecological_season_id: number; - vantage_id: number; + vantage_code_ids: number[]; revision_count?: number; } diff --git a/app/src/test-helpers/survey-helpers.ts b/app/src/test-helpers/survey-helpers.ts index 6ca3bfd988..d900d472e3 100644 --- a/app/src/test-helpers/survey-helpers.ts +++ b/app/src/test-helpers/survey-helpers.ts @@ -53,7 +53,7 @@ export const getSurveyForViewResponse: IGetSurveyForViewResponse = { additional_details: 'details', field_method_id: 1, ecological_season_id: 1, - vantage_id: 1 + vantage_code_ids: [1, 2] }, survey_proprietor: { id: 23, From 089ba8b45e7f70d1ff6aa74b34139117d0025020 Mon Sep 17 00:00:00 2001 From: cgarrettjones Date: Thu, 7 Apr 2022 16:16:12 -0700 Subject: [PATCH 12/66] - removed foreign key from "template methodology species" to "wldtaxonomic units" - added foreign key from "template methodology species" to "intended outcome" --- .../migrations/20220404093900_SIMS.1.1.0.ts | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/database/src/migrations/20220404093900_SIMS.1.1.0.ts b/database/src/migrations/20220404093900_SIMS.1.1.0.ts index 5388a0dea1..39237da1e9 100644 --- a/database/src/migrations/20220404093900_SIMS.1.1.0.ts +++ b/database/src/migrations/20220404093900_SIMS.1.1.0.ts @@ -9,6 +9,13 @@ import { Knex } from 'knex'; */ export async function up(knex: Knex): Promise { await knex.raw(` + set search_path = biohub_dapi_v1; + + drop view survey; + drop view common_survey_methodology; + drop view template_methodology_species; + + set search_path = biohub, public; CREATE TABLE ecological_season( @@ -306,6 +313,22 @@ export async function up(knex: Knex): Promise { create trigger audit_survey_vantage before insert or delete or update on biohub.survey_vantage for each row execute function biohub.tr_audit_trigger(); + alter table template_methodology_species rename Constraint "PK192" to template_methodology_species_pk; + + alter table template_methodology_species rename column common_survey_methodology_id to field_method_id; + + alter table template_methodology_species add column intended_outcome_id integer; + + COMMENT ON COLUMN template_methodology_species.intended_outcome_id IS 'System generated surrogate primary key identifier.'; + + ALTER TABLE template_methodology_species ADD CONSTRAINT "Refintended_outcome217" + FOREIGN KEY (intended_outcome_id) + REFERENCES intended_outcome(intended_outcome_id); + + CREATE INDEX "Ref223217" ON template_methodology_species(intended_outcome_id); + + ALTER TABLE template_methodology_species drop column wldtaxonomic_units_id; + -- api_delete_survey.sql drop procedure if exists api_delete_survey; @@ -419,13 +442,10 @@ export async function up(knex: Knex): Promise { create view vantage as select * from biohub.vantage; create view survey_vantage as select * from biohub.survey_vantage; - drop view survey; create view survey as select * from biohub.survey; - drop view common_survey_methodology; create view field_method as select * from biohub.field_method; - drop view template_methodology_species; create view template_methodology_species as select * from biohub.template_methodology_species; - `); + `); } export async function down(knex: Knex): Promise { From 49e98f165f59e2e18b660ccf7d27fbe0cc4c33c7 Mon Sep 17 00:00:00 2001 From: Anissa Agahchen Date: Thu, 7 Apr 2022 17:34:09 -0700 Subject: [PATCH 13/66] update survey table --- api/src/models/survey-update.ts | 28 +++++++++ .../{projectId}/survey/{surveyId}/update.ts | 42 +++++++++++++- .../queries/survey/survey-update-queries.ts | 57 ++++++++++++++++++- app/src/features/surveys/CreateSurveyPage.tsx | 1 + .../components/PurposeAndMethodologyForm.tsx | 1 + .../SurveyPurposeAndMethodology.tsx | 8 +-- 6 files changed, 126 insertions(+), 11 deletions(-) diff --git a/api/src/models/survey-update.ts b/api/src/models/survey-update.ts index 482e242bdf..16435585b3 100644 --- a/api/src/models/survey-update.ts +++ b/api/src/models/survey-update.ts @@ -152,3 +152,31 @@ export class PutSurveyProprietorData { this.revision_count = obj?.revision_count ?? null; } } + +/** + * Pre-processes PUT /project/{projectId}/survey/{surveyId} survey purpose and methodology data for update + * + * @export + * @class PutSurveyPurposeAndMethodologyData + */ +export class PutSurveyPurposeAndMethodologyData { + id: number; + intended_outcome_id: number; + field_method_id: number; + additional_details: string; + ecological_season_id: number; + vantage_code_ids: number[]; + revision_count: number; + + constructor(obj?: any) { + defaultLog.debug({ label: 'PutSurveyPurposeAndMethodologyData', message: 'params', obj }); + + this.id = obj?.id ?? null; + this.intended_outcome_id = obj?.intended_outcome_id || null; + this.field_method_id = obj?.field_method_id || null; + this.additional_details = obj?.additional_details || null; + this.ecological_season_id = obj?.ecological_season_id || null; + this.vantage_code_ids = (obj?.vantage_code_ids?.length && obj.vantage_code_ids) || []; + this.revision_count = obj?.revision_count ?? null; + } +} diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts index 95b204a046..73f27a2a9e 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts @@ -7,6 +7,7 @@ import { PostSurveyProprietorData } from '../../../../../models/survey-create'; import { GetUpdateSurveyDetailsData, PutSurveyDetailsData, + PutSurveyPurposeAndMethodologyData, PutSurveyProprietorData } from '../../../../../models/survey-update'; import { GetSurveyProprietorData, GetSurveyPurposeAndMethodologyData } from '../../../../../models/survey-view-update'; @@ -302,9 +303,7 @@ export const getSurveyPurposeAndMethodologyData = async ( const response = await connection.query(sqlStatement.text, sqlStatement.values); - return ( - (response && response.rows && response.rows[0] && new GetSurveyPurposeAndMethodologyData(response.rows[0])) || null - ); + return (response && response.rows && new GetSurveyPurposeAndMethodologyData(response.rows)[0]) || null; }; export const getSurveyProprietorData = async ( @@ -357,6 +356,10 @@ export function updateSurvey(): RequestHandler { promises.push(updateSurveyDetailsData(projectId, surveyId, entities, connection)); } + if (entities.survey_purpose_and_methodology) { + promises.push(updateSurveyPurposeAndMethodologyData(surveyId, entities, connection)); + } + if (entities.survey_proprietor) { promises.push(updateSurveyProprietorData(surveyId, entities, connection)); } @@ -544,3 +547,36 @@ export const unassociatePermitFromSurvey = async (survey_id: number, connection: throw new HTTP400('Failed to update survey permit number data'); } }; + +export const updateSurveyPurposeAndMethodologyData = async ( + surveyId: number, + entities: IUpdateSurvey, + connection: IDBConnection +): Promise => { + const putPurposeAndMethodologyData = + (entities?.survey_purpose_and_methodology && + new PutSurveyPurposeAndMethodologyData(entities.survey_purpose_and_methodology)) || + null; + + const revision_count = putPurposeAndMethodologyData?.revision_count ?? null; + + if (!revision_count && revision_count !== 0) { + throw new HTTP400('Failed to parse request body'); + } + + const updateSurveySQLStatement = queries.survey.putSurveyPurposeAndMethodologySQL( + surveyId, + putPurposeAndMethodologyData, + revision_count + ); + + if (!updateSurveySQLStatement) { + throw new HTTP400('Failed to build SQL update statement'); + } + + const result = await connection.query(updateSurveySQLStatement.text, updateSurveySQLStatement.values); + + if (!result || !result.rowCount) { + throw new HTTP409('Failed to update stale survey data'); + } +}; diff --git a/api/src/queries/survey/survey-update-queries.ts b/api/src/queries/survey/survey-update-queries.ts index f915acf139..d02be3abfc 100644 --- a/api/src/queries/survey/survey-update-queries.ts +++ b/api/src/queries/survey/survey-update-queries.ts @@ -1,5 +1,9 @@ import { SQL, SQLStatement } from 'sql-template-strings'; -import { PutSurveyDetailsData, PutSurveyProprietorData } from '../../models/survey-update'; +import { + PutSurveyDetailsData, + PutSurveyProprietorData, + PutSurveyPurposeAndMethodologyData +} from '../../models/survey-update'; import { getLogger } from '../../utils/logger'; import { queries } from '../queries'; @@ -133,14 +137,12 @@ export const putSurveyDetailsSQL = ( UPDATE survey SET name = ${data.name}, - objectives = ${data.objectives}, start_date = ${data.start_date}, end_date = ${data.end_date}, lead_first_name = ${data.lead_first_name}, lead_last_name = ${data.lead_last_name}, location_name = ${data.location_name}, geojson = ${JSON.stringify(data.geometry)}, - common_survey_methodology_id = ${data.common_survey_methodology_id}, geography = `; @@ -262,3 +264,52 @@ export const updateSurveyPublishStatusSQL = (surveyId: number, publish: boolean) return sqlStatement; }; + +/** + * SQL query to update a survey row. + * + * @param {number} projectId + * @param {number} surveyId + * @param {PutSurveyPurposeAndMethodologyData} data + * @returns {SQLStatement} sql query object + */ +export const putSurveyPurposeAndMethodologySQL = ( + surveyId: number, + data: PutSurveyPurposeAndMethodologyData | null, + revision_count: number +): SQLStatement | null => { + defaultLog.debug({ + label: 'putSurveyPurposeAndMethodologySQL', + message: 'params', + surveyId, + data, + revision_count + }); + + if (!surveyId || !data) { + return null; + } + + const sqlStatement = SQL` + UPDATE + survey + SET + field_method_id = ${data.field_method_id}, + additional_details = ${data.additional_details}, + ecological_season_id = ${data.ecological_season_id}, + intended_outcome_id = ${data.intended_outcome_id} + WHERE + survey_id = ${surveyId} + AND + revision_count = ${revision_count}; + `; + + defaultLog.debug({ + label: 'putSurveyPurposeAndMethodologySQL', + message: 'sql', + 'sqlStatement.text': sqlStatement.text, + 'sqlStatement.values': sqlStatement.values + }); + + return sqlStatement; +}; diff --git a/app/src/features/surveys/CreateSurveyPage.tsx b/app/src/features/surveys/CreateSurveyPage.tsx index 29ffd85cb3..667445748c 100644 --- a/app/src/features/surveys/CreateSurveyPage.tsx +++ b/app/src/features/surveys/CreateSurveyPage.tsx @@ -415,6 +415,7 @@ const CreateSurveyPage = () => { return { value: item.id, label: item.name }; }) || [] } + additional_details={''} /> }> diff --git a/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx b/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx index 843ee593a5..df0d0efd58 100644 --- a/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx +++ b/app/src/features/surveys/components/PurposeAndMethodologyForm.tsx @@ -42,6 +42,7 @@ export const PurposeAndMethodologyYupSchema = yup.object().shape({ export interface IPurposeAndMethodologyFormProps { intended_outcomes: IAutocompleteFieldOption[]; + additional_details: string; field_methods: IAutocompleteFieldOption[]; ecological_seasons: IAutocompleteFieldOption[]; vantage_codes: IAutocompleteFieldOption[]; diff --git a/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx b/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx index b42d841e4e..3c35a3eb3f 100644 --- a/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx +++ b/app/src/features/surveys/view/components/SurveyPurposeAndMethodology.tsx @@ -1,18 +1,16 @@ import Box from '@material-ui/core/Box'; import Divider from '@material-ui/core/Divider'; - -import { H3ButtonToolbar } from 'components/toolbar/ActionToolbars'; - import Grid from '@material-ui/core/Grid'; import Typography from '@material-ui/core/Typography'; import { mdiPencilOutline } from '@mdi/js'; import Icon from '@mdi/react'; import EditDialog from 'components/dialog/EditDialog'; import { ErrorDialog, IErrorDialogProps } from 'components/dialog/ErrorDialog'; +import { H3ButtonToolbar } from 'components/toolbar/ActionToolbars'; import { EditSurveyPurposeAndMethodologyI18N } from 'constants/i18n'; import PurposeAndMethodologyForm, { - PurposeAndMethodologyInitialValues, IPurposeAndMethodologyForm, + PurposeAndMethodologyInitialValues, PurposeAndMethodologyYupSchema } from 'features/surveys/components/PurposeAndMethodologyForm'; import { APIError } from 'hooks/api/useAxios'; @@ -53,7 +51,6 @@ const SurveyPurposeAndMethodologyData: React.FC(null); - const [purposeAndMethodologyFormData, setPurposeAndMethodologyFormData] = useState( PurposeAndMethodologyInitialValues ); @@ -172,6 +169,7 @@ const SurveyPurposeAndMethodologyData: React.FC ), initialValues: purposeAndMethodologyFormData, From b515c4ca40c4950149f91fec0e06ebd1d6f4176f Mon Sep 17 00:00:00 2001 From: Anissa Agahchen Date: Thu, 7 Apr 2022 17:41:00 -0700 Subject: [PATCH 14/66] update snapshots --- .../GeneralInformationForm.test.tsx.snap | 376 +----------------- .../__snapshots__/SurveyDetails.test.tsx.snap | 180 +++++++-- .../SurveyGeneralInformation.test.tsx.snap | 66 +-- 3 files changed, 175 insertions(+), 447 deletions(-) diff --git a/app/src/features/surveys/components/__snapshots__/GeneralInformationForm.test.tsx.snap b/app/src/features/surveys/components/__snapshots__/GeneralInformationForm.test.tsx.snap index 563872af9d..3abf702eee 100644 --- a/app/src/features/surveys/components/__snapshots__/GeneralInformationForm.test.tsx.snap +++ b/app/src/features/surveys/components/__snapshots__/GeneralInformationForm.test.tsx.snap @@ -53,52 +53,6 @@ exports[`General Information Form renders correctly the empty component correctl -
-
- -
- - -
-
-
@@ -1099,6 +938,11 @@ exports[`General Information Form renders correctly the filled component correct
+ + Species +
-
-
- -
-
- Recruitment -
- - - -
-

-

-
-
-
- -
- - -
-

- error on survey purpose field -

-
-
@@ -1997,6 +1716,11 @@ exports[`General Information Form renders correctly when errors exist 1`] = `
+ + Species +
-
-
- -
-
- Recruitment -
- - - -
-

-

-
-
-

- survey purpose -

-
-
-
- Survey Methodology -
-
- method -
-
@@ -168,7 +145,7 @@ exports[`SurveyDetails renders correctly 1`] = `
+
+
+
+
+
+
+
+ Intended Outcome +
+
+ Intended Outcome 1 +
+
+
+
+ Additional Details +
+
+ details +
+
+
+
+ Field Method +
+
+ Recruitment +
+
+
+
+
+ Ecological Season +
+
+ Season 1 +
+
+
+
+ Vantage Code +
+
+ Vantage Code 1 +
+
+ Vantage Code 2 +
+
+
+
+
+ +
-
-
- -
-