mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Merge branch 'main' into improve-export-filenames
This commit is contained in:
@@ -40,3 +40,6 @@ The new version is not deployed yet.
|
|||||||
:mag_right: [Class diagram](documentation/class_diagram.md) See the relations of relevant tables. Notice that it omits some unimportant tables and does not show most columns.
|
:mag_right: [Class diagram](documentation/class_diagram.md) See the relations of relevant tables. Notice that it omits some unimportant tables and does not show most columns.
|
||||||
|
|
||||||
:earth_africa: [Map features](documentation/frontend/components/maps/README.md) Maps' functionality and development notes
|
:earth_africa: [Map features](documentation/frontend/components/maps/README.md) Maps' functionality and development notes
|
||||||
|
|
||||||
|
**DeepWiki documentation for the NOW database can be found here:**
|
||||||
|
[](https://deepwiki.com/nowcommunity/nowdatabase)
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ export const newSpeciesBasis: EditDataType<SpeciesDetailsType & EditMetaData> =
|
|||||||
suborder_or_superfamily_name: '',
|
suborder_or_superfamily_name: '',
|
||||||
subfamily_name: 'Soricinae',
|
subfamily_name: 'Soricinae',
|
||||||
genus_name: 'Petenyia',
|
genus_name: 'Petenyia',
|
||||||
species_name: 'dubia test',
|
species_name: 'dubiatest',
|
||||||
unique_identifier: '-',
|
unique_identifier: '-',
|
||||||
taxonomic_status: null,
|
taxonomic_status: '',
|
||||||
common_name: null,
|
common_name: null,
|
||||||
sp_author: 'Bachmayer & Wilson, 1970',
|
sp_author: 'Bachmayer & Wilson, 1970',
|
||||||
strain: null,
|
strain: null,
|
||||||
@@ -145,7 +145,7 @@ export const newSpeciesBasis: EditDataType<SpeciesDetailsType & EditMetaData> =
|
|||||||
export const editedSpecies: EditDataType<SpeciesDetailsType & EditMetaData> = {
|
export const editedSpecies: EditDataType<SpeciesDetailsType & EditMetaData> = {
|
||||||
species_id: 21426,
|
species_id: 21426,
|
||||||
sp_comment: 'Test comment',
|
sp_comment: 'Test comment',
|
||||||
species_name: 'Test species name',
|
species_name: 'Testspeciesname',
|
||||||
now_ls: [{ rowState: 'new', lid: 20920 }],
|
now_ls: [{ rowState: 'new', lid: 20920 }],
|
||||||
com_taxa_synonym: [],
|
com_taxa_synonym: [],
|
||||||
now_sau: [],
|
now_sau: [],
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
import { EditDataType, EditMetaData, LocalityDetailsType, User, Role } from '../../../frontend/src/shared/types'
|
import {
|
||||||
|
EditDataType,
|
||||||
|
EditMetaData,
|
||||||
|
LocalityDetailsType,
|
||||||
|
User,
|
||||||
|
Role,
|
||||||
|
LocalitySpeciesDetailsType,
|
||||||
|
Editable,
|
||||||
|
SpeciesDetailsType,
|
||||||
|
} from '../../../frontend/src/shared/types'
|
||||||
import { validateLocality } from '../../../frontend/src/shared/validators/locality'
|
import { validateLocality } from '../../../frontend/src/shared/validators/locality'
|
||||||
|
import { validateSpecies } from '../../../frontend/src/shared/validators/species'
|
||||||
import { ValidationObject, referenceValidator } from '../../../frontend/src/shared/validators/validator'
|
import { ValidationObject, referenceValidator } from '../../../frontend/src/shared/validators/validator'
|
||||||
import Prisma from '../../prisma/generated/now_test_client'
|
import Prisma from '../../prisma/generated/now_test_client'
|
||||||
import { AccessError } from '../middlewares/authorizer'
|
import { AccessError } from '../middlewares/authorizer'
|
||||||
import { fixBigInt } from '../utils/common'
|
import { fixBigInt } from '../utils/common'
|
||||||
import { logDb, nowDb } from '../utils/db'
|
import { logDb, nowDb } from '../utils/db'
|
||||||
import { logger } from '../utils/logger'
|
|
||||||
import { getReferenceDetails } from './reference'
|
import { getReferenceDetails } from './reference'
|
||||||
|
|
||||||
const getIdsOfUsersProjects = async (user: User) => {
|
const getIdsOfUsersProjects = async (user: User) => {
|
||||||
@@ -200,6 +209,7 @@ export const getLocalityDetails = async (id: number, user: User | undefined) =>
|
|||||||
return JSON.parse(fixBigInt(result)!) as LocalityDetailsType
|
return JSON.parse(fixBigInt(result)!) as LocalityDetailsType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// also validates possible new species that were added to this locality
|
||||||
export const validateEntireLocality = async (editedFields: EditDataType<Prisma.now_loc> & EditMetaData) => {
|
export const validateEntireLocality = async (editedFields: EditDataType<Prisma.now_loc> & EditMetaData) => {
|
||||||
const keys = Object.keys(editedFields)
|
const keys = Object.keys(editedFields)
|
||||||
const errors: ValidationObject[] = []
|
const errors: ValidationObject[] = []
|
||||||
@@ -207,6 +217,17 @@ export const validateEntireLocality = async (editedFields: EditDataType<Prisma.n
|
|||||||
const error = validateLocality(editedFields as EditDataType<LocalityDetailsType>, key as keyof LocalityDetailsType)
|
const error = validateLocality(editedFields as EditDataType<LocalityDetailsType>, key as keyof LocalityDetailsType)
|
||||||
if (error.error) errors.push(error)
|
if (error.error) errors.push(error)
|
||||||
}
|
}
|
||||||
|
if ('now_ls' in editedFields) {
|
||||||
|
for (const species of editedFields.now_ls as Array<Editable<LocalitySpeciesDetailsType>>) {
|
||||||
|
if (species.rowState === 'new') {
|
||||||
|
const keys = Object.keys(species.com_species)
|
||||||
|
for (const key of keys) {
|
||||||
|
const newSpeciesError = validateSpecies(species.com_species, key as keyof SpeciesDetailsType)
|
||||||
|
if (newSpeciesError.error) errors.push(newSpeciesError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let error = null
|
let error = null
|
||||||
if ('references' in editedFields && editedFields.references) {
|
if ('references' in editedFields && editedFields.references) {
|
||||||
error = referenceValidator(editedFields.references)
|
error = referenceValidator(editedFields.references)
|
||||||
@@ -251,12 +272,10 @@ export const filterDuplicateLocalitySpecies = async (
|
|||||||
// Logic is flipped for filter as we want to skip the ones the check matches
|
// Logic is flipped for filter as we want to skip the ones the check matches
|
||||||
return !(localityDetailsSpeciesIds.includes(localitySpecies.species_id) && localitySpecies.rowState === 'new')
|
return !(localityDetailsSpeciesIds.includes(localitySpecies.species_id) && localitySpecies.rowState === 'new')
|
||||||
}
|
}
|
||||||
|
// if localitySpecies doesn't have species_id (i.e. it was created with the "add new species" button in Species tab),
|
||||||
// code shouldn't get here ever
|
// it will never be filtered out. However, due to the taxonomy check for the "add new species" button,
|
||||||
logger.info(
|
// it should not let the user create a duplicate species in this way.
|
||||||
`Filter already existing species: localitySpecies didn't have species_id. Skipping. ${JSON.stringify(localitySpecies)}`
|
return true
|
||||||
)
|
|
||||||
return false
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return updatedLocalityNow_ls
|
return updatedLocalityNow_ls
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ export const writeLocality = async (
|
|||||||
try {
|
try {
|
||||||
await writeHandler.start()
|
await writeHandler.start()
|
||||||
|
|
||||||
const filteredLocality = await filterDuplicateLocalitySpecies(locality, user)
|
const filteredLocalities = await filterDuplicateLocalitySpecies(locality, user)
|
||||||
if (updateOrAdd === 'update' && filteredLocality) {
|
if (updateOrAdd === 'update' && filteredLocalities && filteredLocalities.length > 0) {
|
||||||
locality.now_ls = filteredLocality
|
locality.now_ls = filteredLocalities
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateOrAdd === 'add') {
|
if (updateOrAdd === 'add') {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const getSpeciesWriteHandler = (type: ActionType) => {
|
|||||||
dbName: NOW_DB_NAME,
|
dbName: NOW_DB_NAME,
|
||||||
table: 'com_species',
|
table: 'com_species',
|
||||||
idColumn: 'species_id',
|
idColumn: 'species_id',
|
||||||
allowedColumns: getFieldsOfTables(['com_species', 'now_ls', 'now_sau', 'now_lau']),
|
allowedColumns: getFieldsOfTables(['com_species', 'now_ls', 'now_sau', 'now_lau', 'com_taxa_synonym']),
|
||||||
type,
|
type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+164
-20
@@ -1,3 +1,162 @@
|
|||||||
|
before('Reset database', () => {
|
||||||
|
cy.request(Cypress.env('databaseResetUrl'))
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Adding species in Locality -> Species tab for an existing locality', () => {
|
||||||
|
beforeEach('Login as admin', () => {
|
||||||
|
cy.login('testSu')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('works with valid, unique species', () => {
|
||||||
|
cy.visit(`/locality/20920?tab=2`)
|
||||||
|
cy.contains('Lantian-Shuijiazui')
|
||||||
|
cy.get('[id=edit-button]').click()
|
||||||
|
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.get('[name=order_name]').type('Rodentia')
|
||||||
|
cy.get('[name=family_name]').type('Gliridae')
|
||||||
|
cy.get('[name=genus_name]').type('Simplomys')
|
||||||
|
cy.get('[name=species_name]').type('someSpecies')
|
||||||
|
cy.get('[name=unique_identifier]').type('veryunique')
|
||||||
|
cy.contains('Save').click()
|
||||||
|
cy.contains('somespecies')
|
||||||
|
|
||||||
|
cy.addReferenceAndSave()
|
||||||
|
cy.contains('Edited item successfully.')
|
||||||
|
cy.visit(`/locality/20920?tab=2`)
|
||||||
|
cy.contains('somespecies')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('works through "copy species taxonomy" button', () => {
|
||||||
|
cy.visit(`/locality/20920?tab=2`)
|
||||||
|
cy.contains('Lantian-Shuijiazui')
|
||||||
|
cy.get('[id=edit-button]').click()
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
|
cy.get('[data-cy=add-button-21426]').click()
|
||||||
|
cy.contains('Close').click()
|
||||||
|
cy.get('[name=species_name]').clear()
|
||||||
|
cy.get('[name=species_name]').type('Newspecies')
|
||||||
|
cy.contains('Save').click()
|
||||||
|
|
||||||
|
cy.addReferenceAndSave()
|
||||||
|
cy.contains('Edited item successfully.')
|
||||||
|
cy.visit(`/locality/20920?tab=2`)
|
||||||
|
cy.contains('newspecies')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not work with invalid species', () => {
|
||||||
|
cy.visit(`/locality/20920?tab=2`)
|
||||||
|
cy.contains('Lantian-Shuijiazui')
|
||||||
|
cy.get('[id=edit-button]').click()
|
||||||
|
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.clearNewSpeciesForm()
|
||||||
|
cy.get('[name=order_name]').type('Order with spaces')
|
||||||
|
cy.get('[name=family_name]').type('newfamily')
|
||||||
|
cy.get('[name=genus_name]').type('newgenus')
|
||||||
|
cy.get('[name=species_name]').type('newspecies')
|
||||||
|
cy.get('[name=unique_identifier]').type('veryunique')
|
||||||
|
cy.contains('Save').click()
|
||||||
|
cy.contains('Order must not contain any spaces, unless the value is "incertae sedis".')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not work if the species has already been added', () => {
|
||||||
|
cy.visit(`/locality/20920?tab=2`)
|
||||||
|
cy.contains('Lantian-Shuijiazui')
|
||||||
|
cy.get('[id=edit-button]').click()
|
||||||
|
|
||||||
|
// adding species that already exists in the database
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.clearNewSpeciesForm()
|
||||||
|
cy.get('[name=order_name]').type('Rodentia')
|
||||||
|
cy.get('[name=family_name]').type('Gliridae')
|
||||||
|
cy.get('[name=genus_name]').type('Simplomys')
|
||||||
|
cy.get('[name=species_name]').type('Simplicidens')
|
||||||
|
cy.get('[name=unique_identifier]').type('-')
|
||||||
|
cy.contains('Save').click()
|
||||||
|
cy.contains('The taxon already exists in the database.')
|
||||||
|
|
||||||
|
// add new, unique species
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.clearNewSpeciesForm()
|
||||||
|
cy.get('[name=order_name]').type('neworder')
|
||||||
|
cy.get('[name=family_name]').type('newfamily')
|
||||||
|
cy.get('[name=genus_name]').type('newgenus')
|
||||||
|
cy.get('[name=species_name]').type('newspecies')
|
||||||
|
cy.get('[name=unique_identifier]').type('-')
|
||||||
|
cy.contains('Save').click()
|
||||||
|
|
||||||
|
cy.addReferenceAndSave()
|
||||||
|
cy.contains('Edited item successfully.')
|
||||||
|
cy.visit(`/locality/20920?tab=2`)
|
||||||
|
cy.contains('Lantian-Shuijiazui')
|
||||||
|
cy.get('[id=edit-button]').click()
|
||||||
|
cy.contains('Neworder')
|
||||||
|
|
||||||
|
// adding species that has been added earlier through "add new species" button
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.clearNewSpeciesForm()
|
||||||
|
cy.get('[name=order_name]').type('neworder')
|
||||||
|
cy.get('[name=family_name]').type('newfamily')
|
||||||
|
cy.get('[name=genus_name]').type('newgenus')
|
||||||
|
cy.get('[name=species_name]').type('newspecies')
|
||||||
|
cy.get('[name=unique_identifier]').type('-')
|
||||||
|
cy.contains('Save').click()
|
||||||
|
cy.contains('The taxon already exists in the database.')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not work with species with invalid taxonomic order', () => {
|
||||||
|
cy.visit(`/locality/20920?tab=2`)
|
||||||
|
cy.contains('Lantian-Shuijiazui')
|
||||||
|
cy.get('[id=edit-button]').click()
|
||||||
|
|
||||||
|
// adding species that already exists in the database
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.clearNewSpeciesForm()
|
||||||
|
cy.get('[name=order_name]').type('Rodentia')
|
||||||
|
cy.get('[name=family_name]').type('Soricidae')
|
||||||
|
cy.get('[name=genus_name]').type('Simplomys')
|
||||||
|
cy.get('[name=species_name]').type('Simplicidens')
|
||||||
|
cy.get('[name=unique_identifier]').type('unique')
|
||||||
|
cy.contains('Save').click()
|
||||||
|
cy.contains('Family Soricidae belongs to order Eulipotyphla, not Rodentia.')
|
||||||
|
cy.contains('Genus Simplomys belongs to family Gliridae, not Soricidae.')
|
||||||
|
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.clearNewSpeciesForm()
|
||||||
|
cy.get('[name=order_name]').type('Carnivora')
|
||||||
|
cy.get('[name=family_name]').type('Canidae')
|
||||||
|
cy.get('[name=genus_name]').type('Simplomys')
|
||||||
|
cy.get('[name=species_name]').type('Simplicidens')
|
||||||
|
cy.get('[name=unique_identifier]').type('moreunique')
|
||||||
|
cy.contains('Save').click()
|
||||||
|
cy.contains('Genus Simplomys belongs to family Gliridae, not Canidae.')
|
||||||
|
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.clearNewSpeciesForm()
|
||||||
|
cy.get('[name=order_name]').type('Artiodactyla')
|
||||||
|
cy.get('[name=family_name]').type('Bovidae')
|
||||||
|
cy.get('[name=genus_name]').type('Amblycoptus')
|
||||||
|
cy.get('[name=species_name]').type('indet.')
|
||||||
|
cy.get('[name=unique_identifier]').type('uniquest')
|
||||||
|
cy.contains('Save').click()
|
||||||
|
cy.contains('Genus Amblycoptus belongs to family Soricidae, not Bovidae.')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not work through "copy species taxonomy" button if nothing is changed', () => {
|
||||||
|
cy.visit(`/locality/20920?tab=2`)
|
||||||
|
cy.contains('Lantian-Shuijiazui')
|
||||||
|
cy.get('[id=edit-button]').click()
|
||||||
|
cy.contains('Add new Species').click()
|
||||||
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
|
cy.get('[data-cy=add-button-21052]').click()
|
||||||
|
cy.contains('Close').click()
|
||||||
|
cy.contains('Save').click()
|
||||||
|
cy.contains('The taxon already exists in the database.')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('Creating a new locality', () => {
|
describe('Creating a new locality', () => {
|
||||||
beforeEach('Login as admin', () => {
|
beforeEach('Login as admin', () => {
|
||||||
cy.login('testSu')
|
cy.login('testSu')
|
||||||
@@ -30,13 +189,8 @@ describe('Creating a new locality', () => {
|
|||||||
cy.get('[id=dec_long-textfield]').type('103.67')
|
cy.get('[id=dec_long-textfield]').type('103.67')
|
||||||
cy.get('[id=dms_lat-textfield]').should('have.value', '49 4 12 N')
|
cy.get('[id=dms_lat-textfield]').should('have.value', '49 4 12 N')
|
||||||
cy.get('[id=dms_long-textfield]').should('have.value', '103 40 12 E')
|
cy.get('[id=dms_long-textfield]').should('have.value', '103 40 12 E')
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('Edited item successfully.')
|
cy.contains('Edited item successfully.')
|
||||||
cy.contains('Bugat')
|
cy.contains('Bugat')
|
||||||
cy.get('[id=delete-button]').should('exist')
|
cy.get('[id=delete-button]').should('exist')
|
||||||
@@ -150,15 +304,8 @@ describe('Creating a new locality', () => {
|
|||||||
cy.get('[id=dec_lat-textfield]').type('49.07')
|
cy.get('[id=dec_lat-textfield]').type('49.07')
|
||||||
cy.get('[id=dec_long-textfield]').type('103.67')
|
cy.get('[id=dec_long-textfield]').type('103.67')
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
cy.get('[id=write-button]').should('not.be.disabled')
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
|
|
||||||
|
cy.addReferenceAndSave()
|
||||||
cy.contains('Edited item successfully.')
|
cy.contains('Edited item successfully.')
|
||||||
cy.contains('Bugat')
|
cy.contains('Bugat')
|
||||||
cy.contains('8.676')
|
cy.contains('8.676')
|
||||||
@@ -314,11 +461,8 @@ describe("Locality's coordinate selection map works", () => {
|
|||||||
cy.contains('Central Finland').first().click() // first item on the list
|
cy.contains('Central Finland').first().click() // first item on the list
|
||||||
cy.contains('Latitude: 63.05484, Longitude: 24.75291')
|
cy.contains('Latitude: 63.05484, Longitude: 24.75291')
|
||||||
cy.contains('Save').click()
|
cy.contains('Save').click()
|
||||||
cy.contains('Finalize entry').click()
|
|
||||||
cy.contains('button', 'Add existing reference').click()
|
cy.addReferenceAndSave()
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.visit(`/locality/20920?tab=1`)
|
cy.visit(`/locality/20920?tab=1`)
|
||||||
cy.contains('63.05484')
|
cy.contains('63.05484')
|
||||||
cy.contains('24.75291')
|
cy.contains('24.75291')
|
||||||
|
|||||||
+12
-38
@@ -19,13 +19,7 @@ describe('Creating a species', () => {
|
|||||||
cy.get('[id=species_name-textfield]').type('testSpecies')
|
cy.get('[id=species_name-textfield]').type('testSpecies')
|
||||||
cy.get('[id=unique_identifier-textfield]').type('{backspace}testUniqueIdentifier')
|
cy.get('[id=unique_identifier-textfield]').type('{backspace}testUniqueIdentifier')
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
cy.get('[id=write-button]').should('not.be.disabled')
|
||||||
cy.get('[id=write-button]').click()
|
cy.addReferenceAndSave()
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
|
|
||||||
// tests that values are capitalised and trimmed properly
|
// tests that values are capitalised and trimmed properly
|
||||||
cy.contains('Testsuperorder')
|
cy.contains('Testsuperorder')
|
||||||
@@ -66,12 +60,7 @@ describe('Editing a species', () => {
|
|||||||
cy.get('[id=subfamily_name-textfield]').type('heimo')
|
cy.get('[id=subfamily_name-textfield]').type('heimo')
|
||||||
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
cy.get('[id=write-button]').should('not.be.disabled')
|
||||||
cy.get('[id=write-button]').click()
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('Saved species entry successfully.')
|
cy.contains('Saved species entry successfully.')
|
||||||
cy.contains('Modifiedgenus')
|
cy.contains('Modifiedgenus')
|
||||||
cy.contains('modifiedspecies')
|
cy.contains('modifiedspecies')
|
||||||
@@ -101,14 +90,8 @@ describe('Editing a species', () => {
|
|||||||
|
|
||||||
cy.get('[id=species_name-textfield]').type('newSpecies')
|
cy.get('[id=species_name-textfield]').type('newSpecies')
|
||||||
cy.contains('Species: This field is required').should('not.exist')
|
cy.contains('Species: This field is required').should('not.exist')
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
|
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
|
|
||||||
|
cy.addReferenceAndSave()
|
||||||
cy.contains('Saved species entry successfully.')
|
cy.contains('Saved species entry successfully.')
|
||||||
cy.contains('Newgenus')
|
cy.contains('Newgenus')
|
||||||
cy.contains('newspecies')
|
cy.contains('newspecies')
|
||||||
@@ -126,8 +109,7 @@ describe('Taxonomy checks work', () => {
|
|||||||
|
|
||||||
it('Creating a species that already exists in database does not work', () => {
|
it('Creating a species that already exists in database does not work', () => {
|
||||||
cy.visit('/species/new')
|
cy.visit('/species/new')
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').contains('Copy existing taxonomy')
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').click()
|
|
||||||
cy.get('[data-cy=add-button-21052]').click()
|
cy.get('[data-cy=add-button-21052]').click()
|
||||||
cy.contains('Close').click()
|
cy.contains('Close').click()
|
||||||
cy.get('[id=write-button]').click()
|
cy.get('[id=write-button]').click()
|
||||||
@@ -136,8 +118,7 @@ describe('Taxonomy checks work', () => {
|
|||||||
|
|
||||||
it('Invalid main taxonomy values do not work', () => {
|
it('Invalid main taxonomy values do not work', () => {
|
||||||
cy.visit('/species/new')
|
cy.visit('/species/new')
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').contains('Copy existing taxonomy')
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').click()
|
|
||||||
cy.get('[data-cy=add-button-21052]').click()
|
cy.get('[data-cy=add-button-21052]').click()
|
||||||
cy.contains('Close').click()
|
cy.contains('Close').click()
|
||||||
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier') // change identifier so it's not a duplicate species
|
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier') // change identifier so it's not a duplicate species
|
||||||
@@ -158,8 +139,7 @@ describe('Taxonomy checks work', () => {
|
|||||||
|
|
||||||
it('Invalid superorder/order pair does not work', () => {
|
it('Invalid superorder/order pair does not work', () => {
|
||||||
cy.visit('/species/new')
|
cy.visit('/species/new')
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').contains('Copy existing taxonomy')
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').click()
|
|
||||||
cy.get('[data-cy=add-button-21052]').click()
|
cy.get('[data-cy=add-button-21052]').click()
|
||||||
cy.contains('Close').click()
|
cy.contains('Close').click()
|
||||||
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
||||||
@@ -172,8 +152,7 @@ describe('Taxonomy checks work', () => {
|
|||||||
|
|
||||||
it('Invalid order/suborder/family trio does not work', () => {
|
it('Invalid order/suborder/family trio does not work', () => {
|
||||||
cy.visit('/species/new')
|
cy.visit('/species/new')
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').contains('Copy existing taxonomy')
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').click()
|
|
||||||
cy.get('[data-cy=add-button-84357]').click()
|
cy.get('[data-cy=add-button-84357]').click()
|
||||||
cy.contains('Close').click()
|
cy.contains('Close').click()
|
||||||
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
||||||
@@ -187,8 +166,7 @@ describe('Taxonomy checks work', () => {
|
|||||||
|
|
||||||
it('Invalid suborder/family pair does not work', () => {
|
it('Invalid suborder/family pair does not work', () => {
|
||||||
cy.visit('/species/new')
|
cy.visit('/species/new')
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').contains('Copy existing taxonomy')
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').click()
|
|
||||||
cy.get('[data-cy=add-button-84357]').click()
|
cy.get('[data-cy=add-button-84357]').click()
|
||||||
cy.contains('Close').click()
|
cy.contains('Close').click()
|
||||||
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
||||||
@@ -201,8 +179,7 @@ describe('Taxonomy checks work', () => {
|
|||||||
|
|
||||||
it('Invalid family/subfamily/genus trio does not work', () => {
|
it('Invalid family/subfamily/genus trio does not work', () => {
|
||||||
cy.visit('/species/new')
|
cy.visit('/species/new')
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').contains('Copy existing taxonomy')
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').click()
|
|
||||||
cy.get('[data-cy=add-button-23065]').click()
|
cy.get('[data-cy=add-button-23065]').click()
|
||||||
cy.contains('Close').click()
|
cy.contains('Close').click()
|
||||||
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
||||||
@@ -216,8 +193,7 @@ describe('Taxonomy checks work', () => {
|
|||||||
|
|
||||||
it('Invalid subfamily/genus pair does not work', () => {
|
it('Invalid subfamily/genus pair does not work', () => {
|
||||||
cy.visit('/species/new')
|
cy.visit('/species/new')
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').contains('Copy existing taxonomy')
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').click()
|
|
||||||
cy.get('[data-cy=add-button-23065]').click()
|
cy.get('[data-cy=add-button-23065]').click()
|
||||||
cy.contains('Close').click()
|
cy.contains('Close').click()
|
||||||
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
||||||
@@ -230,8 +206,7 @@ describe('Taxonomy checks work', () => {
|
|||||||
|
|
||||||
it('When genus is indet. species has to be indet.', () => {
|
it('When genus is indet. species has to be indet.', () => {
|
||||||
cy.visit('/species/new')
|
cy.visit('/species/new')
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').contains('Copy existing taxonomy')
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').click()
|
|
||||||
cy.get('[data-cy=add-button-21052]').click()
|
cy.get('[data-cy=add-button-21052]').click()
|
||||||
cy.contains('Close').click()
|
cy.contains('Close').click()
|
||||||
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
||||||
@@ -246,8 +221,7 @@ describe('Taxonomy checks work', () => {
|
|||||||
|
|
||||||
it('When genus is gen. species has to be sp.', () => {
|
it('When genus is gen. species has to be sp.', () => {
|
||||||
cy.visit('/species/new')
|
cy.visit('/species/new')
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').contains('Copy existing taxonomy')
|
cy.get('[data-cy=copy_existing_taxonomy_button]').click()
|
||||||
cy.get('[id=copy_existing_taxonomy_button]').click()
|
|
||||||
cy.get('[data-cy=add-button-21052]').click()
|
cy.get('[data-cy=add-button-21052]').click()
|
||||||
cy.contains('Close').click()
|
cy.contains('Close').click()
|
||||||
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
cy.get('[id=unique_identifier-textfield]').type('{backspace}new identifier')
|
||||||
|
|||||||
@@ -17,12 +17,8 @@ describe('Creating time bound', () => {
|
|||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.get('[id=write-button]').should('be.disabled')
|
||||||
cy.get('[id=age-textfield]').first().type('20')
|
cy.get('[id=age-textfield]').first().type('20')
|
||||||
cy.contains('Age (Ma): This field is required').should('not.exist')
|
cy.contains('Age (Ma): This field is required').should('not.exist')
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('button', 'Add existing reference').click()
|
cy.addReferenceAndSave()
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('Edited item successfully.')
|
cy.contains('Edited item successfully.')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -38,13 +34,8 @@ describe('Editing time bound', () => {
|
|||||||
cy.get('[id=edit-button]').click()
|
cy.get('[id=edit-button]').click()
|
||||||
cy.get('[id=age-textfield]').first().type('{backspace}{backspace}{backspace}{backspace}{backspace}1.5')
|
cy.get('[id=age-textfield]').first().type('{backspace}{backspace}{backspace}{backspace}{backspace}1.5')
|
||||||
cy.contains('This field is required').should('not.exist')
|
cy.contains('This field is required').should('not.exist')
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('Edited item successfully.')
|
cy.contains('Edited item successfully.')
|
||||||
cy.contains('1.5')
|
cy.contains('1.5')
|
||||||
})
|
})
|
||||||
|
|||||||
+16
-56
@@ -16,13 +16,8 @@ describe('Creating a time unit', () => {
|
|||||||
cy.get('[data-cy=add-button-11]').first().click()
|
cy.get('[data-cy=add-button-11]').first().click()
|
||||||
cy.get('[id=low_bnd-tableselection]').first().click() // Select Lower Bound Button
|
cy.get('[id=low_bnd-tableselection]').first().click() // Select Lower Bound Button
|
||||||
cy.get('[data-cy=add-button-14]').first().click()
|
cy.get('[data-cy=add-button-14]').first().click()
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('Testing Time Unit Creation')
|
cy.contains('Testing Time Unit Creation')
|
||||||
cy.contains('ALMAAsianlandmammalage')
|
cy.contains('ALMAAsianlandmammalage')
|
||||||
cy.contains('C2N-o')
|
cy.contains('C2N-o')
|
||||||
@@ -130,13 +125,8 @@ describe('Creating a time unit', () => {
|
|||||||
cy.get('[id=sequence-tableselection]').should('have.value', 'ALMAAsianlandmammalage')
|
cy.get('[id=sequence-tableselection]').should('have.value', 'ALMAAsianlandmammalage')
|
||||||
cy.contains('C2N-o')
|
cy.contains('C2N-o')
|
||||||
cy.contains('C2N-y')
|
cy.contains('C2N-y')
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('C2N-o')
|
cy.contains('C2N-o')
|
||||||
cy.contains('C2N-y')
|
cy.contains('C2N-y')
|
||||||
cy.contains('Creating new time-unit').should('not.exist')
|
cy.contains('Creating new time-unit').should('not.exist')
|
||||||
@@ -151,13 +141,8 @@ describe('Creating a time unit', () => {
|
|||||||
cy.get('[data-cy=add-button-11]').first().click()
|
cy.get('[data-cy=add-button-11]').first().click()
|
||||||
cy.get('[id=low_bnd-tableselection]').first().click()
|
cy.get('[id=low_bnd-tableselection]').first().click()
|
||||||
cy.get('[data-cy=add-button-14]').first().click()
|
cy.get('[data-cy=add-button-14]').first().click()
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('C2N-o')
|
cy.contains('C2N-o')
|
||||||
cy.contains('C2N-y')
|
cy.contains('C2N-y')
|
||||||
cy.get('[id=edit-button]').click()
|
cy.get('[id=edit-button]').click()
|
||||||
@@ -165,13 +150,8 @@ describe('Creating a time unit', () => {
|
|||||||
cy.get('[data-cy=add-button-CalatayudTeruellocalbiozone]').first().click()
|
cy.get('[data-cy=add-button-CalatayudTeruellocalbiozone]').first().click()
|
||||||
cy.get('[id=low_bnd-tableselection]').first().click()
|
cy.get('[id=low_bnd-tableselection]').first().click()
|
||||||
cy.get('[data-cy=add-button-49]').first().click()
|
cy.get('[data-cy=add-button-49]').first().click()
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('CalatayudTeruellocalbiozone')
|
cy.contains('CalatayudTeruellocalbiozone')
|
||||||
cy.contains('Langhian/Serravallian')
|
cy.contains('Langhian/Serravallian')
|
||||||
})
|
})
|
||||||
@@ -189,13 +169,8 @@ describe('Editing a time unit', () => {
|
|||||||
cy.get('[id=tu_display_name-textfield]').should('be.disabled') // name field is disabled when editing
|
cy.get('[id=tu_display_name-textfield]').should('be.disabled') // name field is disabled when editing
|
||||||
cy.get('[id=sequence-tableselection]').first().click()
|
cy.get('[id=sequence-tableselection]').first().click()
|
||||||
cy.get('[data-cy=add-button-ALMAAsianlandmammalage]').first().click()
|
cy.get('[data-cy=add-button-ALMAAsianlandmammalage]').first().click()
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('ALMAAsianlandmammalage')
|
cy.contains('ALMAAsianlandmammalage')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -274,13 +249,8 @@ describe('Editing a time unit', () => {
|
|||||||
cy.get('[id=sequence-tableselection]').should('have.value', 'CalatayudTeruellocalbiozone')
|
cy.get('[id=sequence-tableselection]').should('have.value', 'CalatayudTeruellocalbiozone')
|
||||||
cy.contains('C2N-y')
|
cy.contains('C2N-y')
|
||||||
cy.contains('MioceneLate-low')
|
cy.contains('MioceneLate-low')
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('CalatayudTeruellocalbiozone')
|
cy.contains('CalatayudTeruellocalbiozone')
|
||||||
cy.contains('C2N-y')
|
cy.contains('C2N-y')
|
||||||
cy.contains('MioceneLate-low')
|
cy.contains('MioceneLate-low')
|
||||||
@@ -292,13 +262,8 @@ describe('Editing a time unit', () => {
|
|||||||
cy.get('[id=edit-button]').click()
|
cy.get('[id=edit-button]').click()
|
||||||
cy.get('[id=sequence-tableselection]').first().click()
|
cy.get('[id=sequence-tableselection]').first().click()
|
||||||
cy.get('[data-cy=add-button-easternparatethys]').first().click()
|
cy.get('[data-cy=add-button-easternparatethys]').first().click()
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('Bahean')
|
cy.contains('Bahean')
|
||||||
cy.contains('easternparatethys')
|
cy.contains('easternparatethys')
|
||||||
cy.get('[id=edit-button]').click()
|
cy.get('[id=edit-button]').click()
|
||||||
@@ -307,13 +272,8 @@ describe('Editing a time unit', () => {
|
|||||||
cy.get('[data-cy=add-button-CalatayudTeruellocalbiozone]').first().click()
|
cy.get('[data-cy=add-button-CalatayudTeruellocalbiozone]').first().click()
|
||||||
cy.get('[id=up_bnd-tableselection]').first().click()
|
cy.get('[id=up_bnd-tableselection]').first().click()
|
||||||
cy.get('[data-cy=add-button-14]').first().click()
|
cy.get('[data-cy=add-button-14]').first().click()
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.get('[id=write-button]').should('be.disabled')
|
cy.addReferenceAndSave()
|
||||||
cy.contains('button', 'Add existing reference').click()
|
|
||||||
cy.get('button[data-cy^="add-button"]').first().click()
|
|
||||||
cy.contains('button', 'Close').click()
|
|
||||||
cy.get('[id=write-button]').should('not.be.disabled')
|
|
||||||
cy.get('[id=write-button]').click()
|
|
||||||
cy.contains('CalatayudTeruellocalbiozone')
|
cy.contains('CalatayudTeruellocalbiozone')
|
||||||
cy.contains('C2N-o')
|
cy.contains('C2N-o')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -42,3 +42,28 @@ Cypress.Commands.add('pageForbidden', url => {
|
|||||||
Cypress.Commands.add('resetDatabase', () => {
|
Cypress.Commands.add('resetDatabase', () => {
|
||||||
cy.task('resetDatabase')
|
cy.task('resetDatabase')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// use this once you have edited some data and want to save it
|
||||||
|
Cypress.Commands.add('addReferenceAndSave', () => {
|
||||||
|
cy.get('[id=write-button]').click()
|
||||||
|
cy.get('[id=write-button]').should('be.disabled')
|
||||||
|
cy.contains('button', 'Add existing reference').click()
|
||||||
|
cy.get('button[data-cy^="add-button"]').first().click()
|
||||||
|
cy.contains('button', 'Close').click()
|
||||||
|
cy.get('[id=write-button]').should('not.be.disabled')
|
||||||
|
cy.get('[id=write-button]').click()
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('clearNewSpeciesForm', () => {
|
||||||
|
cy.get('[name=order_name]').clear()
|
||||||
|
cy.get('[name=family_name]').clear()
|
||||||
|
cy.get('[name=genus_name]').clear()
|
||||||
|
cy.get('[name=species_name]').clear()
|
||||||
|
cy.get('[name=subclass_or_superorder_name]').clear()
|
||||||
|
cy.get('[name=suborder_or_superfamily_name]').clear()
|
||||||
|
cy.get('[name=subfamily_name]').clear()
|
||||||
|
cy.get('[name=unique_identifier]').clear()
|
||||||
|
cy.get('[name=taxonomic_status]').clear()
|
||||||
|
cy.get('[name=sp_comment]').clear()
|
||||||
|
cy.get('[name=sp_author]').clear()
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
Current reference types & their field labels / field names (29.09.2024)
|
# Reference types
|
||||||
|
|
||||||
As of 29.09.2024 there is no UI to add more entries however you can do it by altering the db itself.
|
Note: This file is old and should be checked and updated.
|
||||||
|
|
||||||
In the test_data/sqlfiles/now_test.sql code related to adding reference types is around rows 3665-3700 and the fields for the data types are added around rows 3175-3525.
|
Current reference types & their field labels / field names
|
||||||
|
|
||||||
Do concider other options before you try to alter the data by hand.
|
In the `test_data/sqlfiles/now_test.sql` file, code related to adding reference types is around rows 3665-3700 and the fields for the data types are added around rows 3175-3525.
|
||||||
|
|
||||||
|
Do consider other options before you try to alter the data by hand.
|
||||||
|
|
||||||
## Existing fields & their ids
|
## Existing fields & their ids
|
||||||
|
|
||||||
title_primary 1
|
title_primary 1
|
||||||
authors_primary 2
|
authors_primary 2
|
||||||
date_primary 3
|
date_primary 3
|
||||||
@@ -32,237 +35,238 @@ Do concider other options before you try to alter the data by hand.
|
|||||||
exact_date 23
|
exact_date 23
|
||||||
|
|
||||||
"ref_type_id": 1, "ref_type": "Journal"'
|
"ref_type_id": 1, "ref_type": "Journal"'
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
Journal / journal_id
|
Journal / journal_id
|
||||||
Volume / volume
|
Volume / volume
|
||||||
Issue / issue
|
Issue / issue
|
||||||
Start Page / start_page
|
Start Page / start_page
|
||||||
End Page / end_page
|
End Page / end_page
|
||||||
Publisher / publisher
|
Publisher / publisher
|
||||||
City / pub_place
|
City / pub_place
|
||||||
Title of Issue / title_secondary
|
Title of Issue / title_secondary
|
||||||
Editors of Issue / authors_secondary
|
Editors of Issue / authors_secondary
|
||||||
Series Title / title_series
|
Series Title / title_series
|
||||||
ISSN/ISBN / issn_isbn
|
ISSN/ISBN / issn_isbn
|
||||||
Abstract / ref_abstract
|
Abstract / ref_abstract
|
||||||
Web/URL / web_url
|
Web/URL / web_url
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
|
|
||||||
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary, journal
|
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary, journal
|
||||||
|
|
||||||
"ref_type_id": 2, "ref_type": "Book",
|
"ref_type_id": 2, "ref_type": "Book",
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
Edition / volume
|
Edition / volume
|
||||||
Volume / issue
|
Volume / issue
|
||||||
No of Pages / end_page
|
No of Pages / end_page
|
||||||
Publisher / publisher
|
Publisher / publisher
|
||||||
City / pub_place
|
City / pub_place
|
||||||
Editors / authors_secondary
|
Editors / authors_secondary
|
||||||
Series Title / title_series
|
Series Title / title_series
|
||||||
Series Editors / authors_series
|
Series Editors / authors_series
|
||||||
ISBN / issn_isbn
|
ISBN / issn_isbn
|
||||||
Abstract / ref_abstract
|
Abstract / ref_abstract
|
||||||
Web/URL / web_url
|
Web/URL / web_url
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
|
|
||||||
Mandatory fields: title_primary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series
|
Mandatory fields: title_primary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series
|
||||||
|
|
||||||
"ref_type_id": 3, "ref_type": Book Chapter'
|
"ref_type_id": 3, "ref_type": Book Chapter'
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
Edition / volume
|
Edition / volume
|
||||||
Chapter No / issue
|
Chapter No / issue
|
||||||
Start Page / start_page
|
Start Page / start_page
|
||||||
End Page / end_page
|
End Page / end_page
|
||||||
Publisher / publisher
|
Publisher / publisher
|
||||||
City / pub_place
|
City / pub_place
|
||||||
Book Title / title_secondary
|
Book Title / title_secondary
|
||||||
Editors / authors_secondary
|
Editors / authors_secondary
|
||||||
Series Title / title_series
|
Series Title / title_series
|
||||||
Series Editors / authors_series
|
Series Editors / authors_series
|
||||||
ISBN / issn_isbn
|
ISBN / issn_isbn
|
||||||
Abstract / ref_abstract
|
Abstract / ref_abstract
|
||||||
Web/URL / web_url
|
Web/URL / web_url
|
||||||
Volume / misc_2
|
Volume / misc_2
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
|
|
||||||
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series
|
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series
|
||||||
|
|
||||||
"ref_type_id": 4, "ref_type": Thesis/Dissertation'
|
"ref_type_id": 4, "ref_type": Thesis/Dissertation'
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
No of Pages / end_page
|
No of Pages / end_page
|
||||||
Institution / publisher
|
Institution / publisher
|
||||||
Abstract / ref_abstract
|
Abstract / ref_abstract
|
||||||
Web/URL / web_url
|
Web/URL / web_url
|
||||||
Degree / misc_1
|
Degree / misc_1
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
|
|
||||||
Mandatory fields: title_primary OR gen_notes, date_primary, authors_primary
|
Mandatory fields: title_primary OR gen_notes, date_primary, authors_primary
|
||||||
|
|
||||||
"ref_type_id": 5, "ref_type": Conference Proceeding'
|
"ref_type_id": 5, "ref_type": Conference Proceeding'
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Publication Year / date_primary
|
Publication Year / date_primary
|
||||||
Journal / journal_id
|
Journal / journal_id
|
||||||
Volume / volume
|
Volume / volume
|
||||||
Edition / issue
|
Edition / issue
|
||||||
Start Page / start_page
|
Start Page / start_page
|
||||||
End Page / end_page
|
End Page / end_page
|
||||||
Publisher / publisher
|
Publisher / publisher
|
||||||
City / pub_place
|
City / pub_place
|
||||||
Title of Conference / title_secondary
|
Title of Conference / title_secondary
|
||||||
Editors / authors_secondary
|
Editors / authors_secondary
|
||||||
Year of Conference / date_secondary
|
Year of Conference / date_secondary
|
||||||
Series Title / title_series
|
Series Title / title_series
|
||||||
Series Editors / authors_series
|
Series Editors / authors_series
|
||||||
Abstract / ref_abstract
|
Abstract / ref_abstract
|
||||||
Web/URL / web_url
|
Web/URL / web_url
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
|
|
||||||
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series, journal
|
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series, journal
|
||||||
|
|
||||||
"ref_type_id": 6, "ref_type": Electronic Citation'
|
"ref_type_id": 6, "ref_type": Electronic Citation'
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Last Update (Year) / date_primary
|
Last Update (Year) / date_primary
|
||||||
Organisation / title_secondary
|
Organisation / title_secondary
|
||||||
Editors / authors_secondary
|
Editors / authors_secondary
|
||||||
Abstract / ref_abstract
|
Abstract / ref_abstract
|
||||||
Web/URL / web_url
|
Web/URL / web_url
|
||||||
Last Update (Day Month) / misc_1
|
Last Update (Day Month) / misc_1
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
Access Date / exact_date
|
Access Date / exact_date
|
||||||
|
|
||||||
Mandatory fields: title_primary OR title_secondary OR gen_notes, date_primary, authors_primary OR authors_secondary, exact_date
|
Mandatory fields: title_primary OR title_secondary OR gen_notes, date_primary, authors_primary OR authors_secondary, exact_date
|
||||||
|
|
||||||
"ref_type_id": 7, "ref_type": Internet Communication'
|
"ref_type_id": 7, "ref_type": Internet Communication'
|
||||||
Subject / title_primary
|
Subject / title_primary
|
||||||
Sender / authors_primary
|
Sender / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
Recipient / authors_secondary
|
Recipient / authors_secondary
|
||||||
Sender's e-mail / misc_1
|
Sender's e-mail / misc_1
|
||||||
Recipient's e-mail / misc_2
|
Recipient's e-mail / misc_2
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
Date of Message / exact_date
|
Date of Message / exact_date
|
||||||
|
|
||||||
Mandatory fields: title_primary OR gen_notes, date_primary, authors_primary OR authors_secondary, exact_date
|
Mandatory fields: title_primary OR gen_notes, date_primary, authors_primary OR authors_secondary, exact_date
|
||||||
|
|
||||||
"ref_type_id": 8, "ref_type": Report'
|
"ref_type_id": 8, "ref_type": Report'
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
Report Number / volume
|
Report Number / volume
|
||||||
Start Page / start_page
|
Start Page / start_page
|
||||||
End Page / end_page
|
End Page / end_page
|
||||||
Publisher / publisher
|
Publisher / publisher
|
||||||
Pub Place / pub_place
|
Pub Place / pub_place
|
||||||
Report Name / title_secondary
|
Report Name / title_secondary
|
||||||
Editors / authors_secondary
|
Editors / authors_secondary
|
||||||
Series Title / title_series
|
Series Title / title_series
|
||||||
Series Editors / authors_series
|
Series Editors / authors_series
|
||||||
Abstract / ref_abstract
|
Abstract / ref_abstract
|
||||||
Web/URL / web_url
|
Web/URL / web_url
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
|
|
||||||
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series
|
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series
|
||||||
|
|
||||||
"ref_type_id": 9, "ref_type": Unpublished Work'
|
"ref_type_id": 9, "ref_type": Unpublished Work'
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
Organisation / title_secondary
|
Organisation / title_secondary
|
||||||
Editors / authors_secondary
|
Editors / authors_secondary
|
||||||
Series Title / title_series
|
Series Title / title_series
|
||||||
Series Editors / authors_series
|
Series Editors / authors_series
|
||||||
Abstract / ref_abstract
|
Abstract / ref_abstract
|
||||||
Web/URL / web_url
|
Web/URL / web_url
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
|
|
||||||
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series
|
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series
|
||||||
|
|
||||||
"ref_type_id": 10, "ref_type": Personal Communication'
|
"ref_type_id": 10, "ref_type": Personal Communication'
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
Recipients / authors_secondary
|
Recipients / authors_secondary
|
||||||
Type / misc_1
|
Type / misc_1
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
Date Sent / exact_date
|
Date Sent / exact_date
|
||||||
|
|
||||||
Mandatory fields: gen_notes, date_primary, authors_primary OR authors_secondary, exact_date
|
Mandatory fields: gen_notes, date_primary, authors_primary OR authors_secondary, exact_date
|
||||||
|
|
||||||
"ref_type_id": 11, "ref_type": Manuscript'
|
"ref_type_id": 11, "ref_type": Manuscript'
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Date / date_primary
|
Date / date_primary
|
||||||
Organisation / title_secondary
|
Organisation / title_secondary
|
||||||
Editors / authors_secondary
|
Editors / authors_secondary
|
||||||
Series Title / title_series
|
Series Title / title_series
|
||||||
Series Editors / authors_series
|
Series Editors / authors_series
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Language / printed_language
|
Language / printed_language
|
||||||
Date / exact_date
|
Date / exact_date
|
||||||
|
|
||||||
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series, exact_date
|
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series, exact_date
|
||||||
|
|
||||||
"ref_type_id": 12, "ref_type": Notes'
|
"ref_type_id": 12, "ref_type": Notes'
|
||||||
Subject / title_primary
|
Subject / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Date / exact_date
|
Date / exact_date
|
||||||
|
|
||||||
Mandatory fields: title_primary OR gen_notes, date_primary, authors_primary, exact_date
|
Mandatory fields: title_primary OR gen_notes, date_primary, authors_primary, exact_date
|
||||||
|
|
||||||
"ref_type_id": 13, "ref_type": Editing'
|
"ref_type_id": 13, "ref_type": Editing'
|
||||||
Title / title_primary
|
Title / title_primary
|
||||||
Authors / authors_primary
|
Authors / authors_primary
|
||||||
Year / date_primary
|
Year / date_primary
|
||||||
Notes / gen_notes
|
Notes / gen_notes
|
||||||
Date / exact_date
|
Date / exact_date
|
||||||
|
|
||||||
Mandatory fields: title_primary OR gen_notes, date_primary, authors_primary, exact_date
|
Mandatory fields: title_primary OR gen_notes, date_primary, authors_primary, exact_date
|
||||||
|
|
||||||
"ref_type_id": 14, "ref_type": Undefined'
|
"ref_type_id": 14, "ref_type": Undefined'
|
||||||
title_primary / title_primary
|
title_primary / title_primary
|
||||||
authors_primary / authors_primary
|
authors_primary / authors_primary
|
||||||
date_primary / date_primary
|
date_primary / date_primary
|
||||||
journal_id / journal_id
|
journal_id / journal_id
|
||||||
volume / volume
|
volume / volume
|
||||||
issue / issue
|
issue / issue
|
||||||
start_page / start_page
|
start_page / start_page
|
||||||
end_page / end_page
|
end_page / end_page
|
||||||
publisher / publisher
|
publisher / publisher
|
||||||
pub_place / pub_place
|
pub_place / pub_place
|
||||||
title_secondary / title_secondary
|
title_secondary / title_secondary
|
||||||
authors_secondary / authors_secondary
|
authors_secondary / authors_secondary
|
||||||
date_secondary / date_secondary
|
date_secondary / date_secondary
|
||||||
title_series / title_series
|
title_series / title_series
|
||||||
authors_series / authors_series
|
authors_series / authors_series
|
||||||
issn_isbn / issn_isbn
|
issn_isbn / issn_isbn
|
||||||
abstract / abstract
|
abstract / abstract
|
||||||
web_url / web_url
|
web_url / web_url
|
||||||
misc_1 / misc_1
|
misc_1 / misc_1
|
||||||
misc_2 / misc_2
|
misc_2 / misc_2
|
||||||
gen_notes / gen_notes
|
gen_notes / gen_notes
|
||||||
language / language
|
language / language
|
||||||
exact_date / exact_date
|
exact_date / exact_date
|
||||||
|
|
||||||
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series, exact_date, journal
|
Mandatory fields: title_primary OR title_secondary OR title_series OR gen_notes, date_primary, authors_primary OR authors_secondary OR authors_series, exact_date, journal
|
||||||
* In old php test version instead of journal, journal_id had to be defined. That seems odd, since when creating a new journal, journal_id will not initally be defined. So that will not be done here.
|
|
||||||
|
- In old php test version instead of journal, journal_id had to be defined. That seems odd, since when creating a new journal, journal_id will not initially be defined. So that will not be done here.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Localities
|
# Species
|
||||||
|
|
||||||
## Required fields
|
## Required fields
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
### Time Bound
|
### Time Bounds
|
||||||
|
|
||||||
A Time Bound can be given the following information:
|
A Time Bound can be given the following information:
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
### Time Unit
|
### Time Units
|
||||||
|
|
||||||
A Time Unit can be given the following information:
|
A Time Unit can be given the following information:
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { EditingModal } from './EditingModal'
|
|||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import { Editable, EditDataType } from '@/shared/types'
|
import { Editable, EditDataType } from '@/shared/types'
|
||||||
import { useDetailContext } from '../Context/DetailContext'
|
import { useDetailContext } from '../Context/DetailContext'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
export type EditingFormField = { name: string; label: string; required?: boolean; type?: 'number' | 'string' }
|
export type EditingFormField = { name: string; label: string; required?: boolean; type?: 'number' | 'string' }
|
||||||
|
|
||||||
@@ -11,6 +12,10 @@ Renders a button, that will open EditingModal, which can be used
|
|||||||
to add a new entry to a list, or edit existing one.
|
to add a new entry to a list, or edit existing one.
|
||||||
If using for adding new, provide arrayFieldName.
|
If using for adding new, provide arrayFieldName.
|
||||||
For editing existing row, use existingObject and editAction.
|
For editing existing row, use existingObject and editAction.
|
||||||
|
|
||||||
|
If you want to autofill the form's fields once the user e.g. clicks a button,
|
||||||
|
pass the updated values into the replacedValues prop. The form will be reset and uses those values.
|
||||||
|
The copyTaxonomyButton prop is used only in Locality -> Species tab.
|
||||||
*/
|
*/
|
||||||
export const EditingForm = <T extends object, ParentType extends object>({
|
export const EditingForm = <T extends object, ParentType extends object>({
|
||||||
dataCy,
|
dataCy,
|
||||||
@@ -19,6 +24,8 @@ export const EditingForm = <T extends object, ParentType extends object>({
|
|||||||
editAction,
|
editAction,
|
||||||
existingObject,
|
existingObject,
|
||||||
arrayFieldName,
|
arrayFieldName,
|
||||||
|
replacedValues,
|
||||||
|
copyTaxonomyButton,
|
||||||
}: {
|
}: {
|
||||||
dataCy?: string
|
dataCy?: string
|
||||||
buttonText: string
|
buttonText: string
|
||||||
@@ -26,15 +33,22 @@ export const EditingForm = <T extends object, ParentType extends object>({
|
|||||||
arrayFieldName?: keyof ParentType
|
arrayFieldName?: keyof ParentType
|
||||||
editAction?: (newObject: T) => void
|
editAction?: (newObject: T) => void
|
||||||
existingObject?: T | undefined
|
existingObject?: T | undefined
|
||||||
|
replacedValues?: T | undefined
|
||||||
|
copyTaxonomyButton?: JSX.Element | undefined
|
||||||
}) => {
|
}) => {
|
||||||
const getDefaultValues: () => { [x: string]: unknown } = () => {
|
const getDefaultValues: () => { [x: string]: unknown } = () => {
|
||||||
if (!existingObject) return {}
|
if (!existingObject) return {}
|
||||||
return existingObject
|
return existingObject
|
||||||
}
|
}
|
||||||
const { register, trigger, formState, getValues } = useForm({ defaultValues: getDefaultValues() })
|
const { register, trigger, formState, getValues, reset } = useForm({ defaultValues: getDefaultValues() })
|
||||||
const { errors } = formState
|
const { errors } = formState
|
||||||
const { editData, setEditData } = useDetailContext<ParentType>()
|
const { editData, setEditData } = useDetailContext<ParentType>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (replacedValues) reset(replacedValues)
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [replacedValues])
|
||||||
|
|
||||||
const onSave = async () => {
|
const onSave = async () => {
|
||||||
const result = await trigger()
|
const result = await trigger()
|
||||||
if (!result) return false
|
if (!result) return false
|
||||||
@@ -52,9 +66,11 @@ export const EditingForm = <T extends object, ParentType extends object>({
|
|||||||
return (
|
return (
|
||||||
<EditingModal {...{ dataCy, buttonText, onSave }}>
|
<EditingModal {...{ dataCy, buttonText, onSave }}>
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '1em' }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '1em' }}>
|
||||||
|
{copyTaxonomyButton}
|
||||||
{formFields.map(field => (
|
{formFields.map(field => (
|
||||||
<TextField
|
<TextField
|
||||||
key={field.name}
|
key={field.name}
|
||||||
|
slotProps={{ inputLabel: { shrink: true } }}
|
||||||
{...register(field.name, {
|
{...register(field.name, {
|
||||||
required: field.required ? 'This field is required' : false,
|
required: field.required ? 'This field is required' : false,
|
||||||
...(field.type === 'number' && {
|
...(field.type === 'number' && {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ give an array in prop "selectedValues" that contains the string values
|
|||||||
that already exist in editdata
|
that already exist in editdata
|
||||||
*/
|
*/
|
||||||
export const SelectingTable = <T extends MRT_RowData, ParentType extends object>({
|
export const SelectingTable = <T extends MRT_RowData, ParentType extends object>({
|
||||||
|
dataCy,
|
||||||
buttonText,
|
buttonText,
|
||||||
data,
|
data,
|
||||||
columns,
|
columns,
|
||||||
@@ -24,6 +25,7 @@ export const SelectingTable = <T extends MRT_RowData, ParentType extends object>
|
|||||||
isError,
|
isError,
|
||||||
useObject,
|
useObject,
|
||||||
}: {
|
}: {
|
||||||
|
dataCy?: string
|
||||||
buttonText: string
|
buttonText: string
|
||||||
data: T[] | undefined
|
data: T[] | undefined
|
||||||
columns: MRT_ColumnDef<T>[]
|
columns: MRT_ColumnDef<T>[]
|
||||||
@@ -71,7 +73,7 @@ export const SelectingTable = <T extends MRT_RowData, ParentType extends object>
|
|||||||
if (isError) return <Box>Error fetching data for the selecting table.</Box>
|
if (isError) return <Box>Error fetching data for the selecting table.</Box>
|
||||||
if (!data) return <CircularProgress />
|
if (!data) return <CircularProgress />
|
||||||
return (
|
return (
|
||||||
<EditingModal buttonText={buttonText}>
|
<EditingModal buttonText={buttonText} dataCy={dataCy}>
|
||||||
{data ? (
|
{data ? (
|
||||||
<TableView<T>
|
<TableView<T>
|
||||||
data={filteredData}
|
data={filteredData}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export const emptyLocality = {
|
|||||||
} as unknown as LocalityDetailsType
|
} as unknown as LocalityDetailsType
|
||||||
|
|
||||||
export const emptySpecies = {
|
export const emptySpecies = {
|
||||||
class_name: '',
|
class_name: 'Mammalia',
|
||||||
order_name: '',
|
order_name: '',
|
||||||
family_name: '',
|
family_name: '',
|
||||||
subclass_or_superorder_name: '',
|
subclass_or_superorder_name: '',
|
||||||
@@ -128,7 +128,7 @@ export const emptySpecies = {
|
|||||||
genus_name: '',
|
genus_name: '',
|
||||||
species_name: '',
|
species_name: '',
|
||||||
unique_identifier: '-',
|
unique_identifier: '-',
|
||||||
taxonomic_status: null,
|
taxonomic_status: '',
|
||||||
common_name: '',
|
common_name: '',
|
||||||
sp_author: '',
|
sp_author: '',
|
||||||
strain: null,
|
strain: null,
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ import { useDetailContext } from './Context/DetailContext'
|
|||||||
import { EditDataType, Editable, Reference, Species } from '@/shared/types'
|
import { EditDataType, Editable, Reference, Species } from '@/shared/types'
|
||||||
import { useState, useEffect, Fragment } from 'react'
|
import { useState, useEffect, Fragment } from 'react'
|
||||||
import { referenceValidator } from '@/shared/validators/validator'
|
import { referenceValidator } from '@/shared/validators/validator'
|
||||||
import { checkTaxonomy, convertTaxonomyFields } from '../../util/taxonomyFunctions'
|
import { checkSpeciesTaxonomy, convertSpeciesTaxonomyFields } from '../../util/taxonomyUtilities'
|
||||||
import { useLazyGetAllSpeciesQuery, useLazyGetAllSynonymsQuery } from '@/redux/speciesReducer'
|
import { useGetAllSpeciesQuery, useGetAllSynonymsQuery } from '@/redux/speciesReducer'
|
||||||
import { useNotify } from '@/hooks/notification'
|
import { useNotify } from '@/hooks/notification'
|
||||||
import { countryBoundingBoxes } from '@/country_data/countryBoundingBoxes'
|
import { countryBoundingBoxes } from '@/country_data/countryBoundingBoxes'
|
||||||
import { boundingBoxSplit, isPointInBoxes } from '@/util/isPointInBox'
|
import { boundingBoxSplit, isPointInBoxes } from '@/util/isPointInBox'
|
||||||
import { OutOfBoundsWarningModal, OutOfBoundsWarningModalState } from './OutOfBoundsWarningModal'
|
import { OutOfBoundsWarningModal, OutOfBoundsWarningModalState } from './OutOfBoundsWarningModal'
|
||||||
|
import { skipToken } from '@reduxjs/toolkit/query'
|
||||||
|
|
||||||
export const WriteButton = <T,>({
|
export const WriteButton = <T,>({
|
||||||
onWrite,
|
onWrite,
|
||||||
@@ -28,8 +29,8 @@ export const WriteButton = <T,>({
|
|||||||
useDetailContext<T>()
|
useDetailContext<T>()
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const { notify } = useNotify()
|
const { notify } = useNotify()
|
||||||
const [getSpeciesData] = useLazyGetAllSpeciesQuery()
|
const { data: speciesData } = useGetAllSpeciesQuery(!taxonomy ? skipToken : undefined)
|
||||||
const [getSynonyms] = useLazyGetAllSynonymsQuery()
|
const { data: synonymData } = useGetAllSynonymsQuery(!taxonomy ? skipToken : undefined)
|
||||||
|
|
||||||
// For coordinate out of bounds warning
|
// For coordinate out of bounds warning
|
||||||
const [warningModalState, setWarningModalState] = useState<OutOfBoundsWarningModalState>({
|
const [warningModalState, setWarningModalState] = useState<OutOfBoundsWarningModalState>({
|
||||||
@@ -50,6 +51,11 @@ export const WriteButton = <T,>({
|
|||||||
return !isPointInBoxes(dec_lat, dec_long, boundingBoxSplit(countryBoundingBoxes[country]))
|
return !isPointInBoxes(dec_lat, dec_long, boundingBoxSplit(countryBoundingBoxes[country]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (taxonomy && (!speciesData || !synonymData)) setLoading(true)
|
||||||
|
else setLoading(false)
|
||||||
|
}, [speciesData, synonymData])
|
||||||
|
|
||||||
/* validates all fields when entering new/editing mode
|
/* validates all fields when entering new/editing mode
|
||||||
to disable write button when unvisited tabs have
|
to disable write button when unvisited tabs have
|
||||||
validation errors (e.g. missing required fields) */
|
validation errors (e.g. missing required fields) */
|
||||||
@@ -107,23 +113,21 @@ export const WriteButton = <T,>({
|
|||||||
// @ts-expect-error Reason: Typescript doesn't recognise that references do exist. Unable to find a way around it. Fix if extra time
|
// @ts-expect-error Reason: Typescript doesn't recognise that references do exist. Unable to find a way around it. Fix if extra time
|
||||||
}, [mode, editData.references])
|
}, [mode, editData.references])
|
||||||
|
|
||||||
const writeWithTaxonomyCheck = async () => {
|
const writeWithTaxonomyCheck = () => {
|
||||||
let speciesEditData: EditDataType<Species> | undefined = undefined
|
let speciesEditData: EditDataType<Species> | undefined = undefined
|
||||||
|
|
||||||
if (!mode.staging) {
|
if (!mode.staging) {
|
||||||
const { data: speciesData } = await getSpeciesData(undefined, true)
|
|
||||||
const { data: synonyms } = await getSynonyms(undefined, true)
|
|
||||||
if (!speciesData) {
|
if (!speciesData) {
|
||||||
notify('Could not fetch species to check taxonomy data.', 'error')
|
notify('Could not fetch species to check taxonomy data.', 'error')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!synonyms) {
|
if (!synonymData) {
|
||||||
notify('Could not fetch synonyms to check taxonomy data.', 'error')
|
notify('Could not fetch synonyms to check taxonomy data.', 'error')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// converts taxonomy fields to capitalized/lowercased
|
// converts taxonomy fields to capitalized/lowercased
|
||||||
speciesEditData = convertTaxonomyFields(editData as EditDataType<Species>)
|
speciesEditData = convertSpeciesTaxonomyFields(editData as EditDataType<Species>)
|
||||||
const errors = checkTaxonomy(speciesEditData, speciesData, synonyms)
|
const errors = checkSpeciesTaxonomy(speciesEditData, speciesData, synonymData)
|
||||||
if (errors.size > 0) {
|
if (errors.size > 0) {
|
||||||
const errorMessage = [...errors].reduce((acc, currentError) => acc + `\n${currentError}`)
|
const errorMessage = [...errors].reduce((acc, currentError) => acc + `\n${currentError}`)
|
||||||
notify(errorMessage, 'error', null)
|
notify(errorMessage, 'error', null)
|
||||||
@@ -144,10 +148,10 @@ export const WriteButton = <T,>({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleWriteButtonClick = async () => {
|
const handleWriteButtonClick = () => {
|
||||||
if (taxonomy) {
|
if (taxonomy) {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
await writeWithTaxonomyCheck()
|
writeWithTaxonomyCheck()
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -186,13 +190,13 @@ export const WriteButton = <T,>({
|
|||||||
!('dec_long' in (editData as object)) ||
|
!('dec_long' in (editData as object)) ||
|
||||||
!('country' in (editData as object))
|
!('country' in (editData as object))
|
||||||
) {
|
) {
|
||||||
void handleWriteButtonClick()
|
handleWriteButtonClick()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const localityObject = editData as unknown as { dec_lat: number; dec_long: number; country: string }
|
const localityObject = editData as unknown as { dec_lat: number; dec_long: number; country: string }
|
||||||
if (!isCoordinateOutOfBounds(localityObject.dec_lat, localityObject.dec_long, localityObject.country)) {
|
if (!isCoordinateOutOfBounds(localityObject.dec_lat, localityObject.dec_long, localityObject.country)) {
|
||||||
void handleWriteButtonClick()
|
handleWriteButtonClick()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,104 @@
|
|||||||
import { LocalityDetailsType, LocalitySpecies, Species, SpeciesDetailsType } from '@/shared/types'
|
import {
|
||||||
|
Editable,
|
||||||
|
EditDataType,
|
||||||
|
LocalityDetailsType,
|
||||||
|
LocalitySpecies,
|
||||||
|
Species,
|
||||||
|
SpeciesDetailsType,
|
||||||
|
} from '@/shared/types'
|
||||||
import { EditableTable } from '@/components/DetailView/common/EditableTable'
|
import { EditableTable } from '@/components/DetailView/common/EditableTable'
|
||||||
import { EditingForm } from '@/components/DetailView/common/EditingForm'
|
import { EditingForm } from '@/components/DetailView/common/EditingForm'
|
||||||
import { SelectingTable } from '@/components/DetailView/common/SelectingTable'
|
import { SelectingTable } from '@/components/DetailView/common/SelectingTable'
|
||||||
import { Grouped } from '@/components/DetailView/common/tabLayoutHelpers'
|
import { Grouped } from '@/components/DetailView/common/tabLayoutHelpers'
|
||||||
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
||||||
import { useGetAllSpeciesQuery } from '@/redux/speciesReducer'
|
import { useGetAllSpeciesQuery } from '@/redux/speciesReducer'
|
||||||
import { Box } from '@mui/material'
|
import { Box, CircularProgress } from '@mui/material'
|
||||||
import { skipToken } from '@reduxjs/toolkit/query'
|
import { skipToken } from '@reduxjs/toolkit/query'
|
||||||
import { MRT_ColumnDef } from 'material-react-table'
|
import { MRT_ColumnDef } from 'material-react-table'
|
||||||
|
import {
|
||||||
|
checkSpeciesTaxonomy,
|
||||||
|
convertSpeciesTaxonomyFields,
|
||||||
|
fixNullValuesInTaxonomyFields,
|
||||||
|
} from '@/util/taxonomyUtilities'
|
||||||
|
import { useNotify } from '@/hooks/notification'
|
||||||
|
import { validateSpecies } from '@/shared/validators/species'
|
||||||
|
import { smallSpeciesTableColumns } from '@/common'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { SynonymsModal } from '@/components/Species/SynonymsModal'
|
||||||
|
|
||||||
export const SpeciesTab = () => {
|
export const SpeciesTab = () => {
|
||||||
const { mode, editData, setEditData } = useDetailContext<LocalityDetailsType>()
|
const { mode, editData, setEditData } = useDetailContext<LocalityDetailsType>()
|
||||||
const { data: speciesData, isError } = useGetAllSpeciesQuery(mode.read ? skipToken : undefined)
|
const { data: speciesData, isError } = useGetAllSpeciesQuery(mode.read ? skipToken : undefined)
|
||||||
|
const { notify } = useNotify()
|
||||||
|
const [replacedValues, setReplacedValues] = useState<EditDataType<Species> | undefined>()
|
||||||
|
const [selectedSpecies, setSelectedSpecies] = useState<string | undefined>()
|
||||||
|
const [modalOpen, setModalOpen] = useState<boolean>(false)
|
||||||
|
|
||||||
|
const handleRowActionClick = (row: Species) => {
|
||||||
|
setSelectedSpecies(row.species_id.toString())
|
||||||
|
setModalOpen(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyTaxonomyButton = (
|
||||||
|
<Box key="copy_existing_taxonomy_button">
|
||||||
|
<SelectingTable<Species, Species>
|
||||||
|
dataCy="copy_existing_taxonomy_button"
|
||||||
|
buttonText="Copy existing taxonomy"
|
||||||
|
data={speciesData}
|
||||||
|
isError={isError}
|
||||||
|
columns={smallSpeciesTableColumns}
|
||||||
|
fieldName="order_name" // this doesn't do anything here but is required
|
||||||
|
idFieldName="species_id"
|
||||||
|
useObject={true}
|
||||||
|
tableRowAction={handleRowActionClick}
|
||||||
|
editingAction={(selectedSpecies: Species) => {
|
||||||
|
const fixedSpecies = fixNullValuesInTaxonomyFields(selectedSpecies)
|
||||||
|
setReplacedValues({
|
||||||
|
subclass_or_superorder_name: fixedSpecies.subclass_or_superorder_name,
|
||||||
|
order_name: fixedSpecies.order_name!,
|
||||||
|
suborder_or_superfamily_name: fixedSpecies.suborder_or_superfamily_name,
|
||||||
|
family_name: fixedSpecies.family_name!,
|
||||||
|
subfamily_name: fixedSpecies.subfamily_name,
|
||||||
|
genus_name: fixedSpecies.genus_name!,
|
||||||
|
species_name: fixedSpecies.species_name!,
|
||||||
|
unique_identifier: fixedSpecies.unique_identifier!,
|
||||||
|
taxonomic_status: '',
|
||||||
|
sp_comment: '',
|
||||||
|
sp_author: '',
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SynonymsModal open={modalOpen} onClose={() => setModalOpen(false)} selectedSpecies={selectedSpecies} />
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
|
||||||
|
const convertAndCheckNewSpeciesTaxonomy = (newSpecies: EditDataType<Species>) => {
|
||||||
|
const errors = []
|
||||||
|
for (const field in newSpecies) {
|
||||||
|
const errorObject = validateSpecies(
|
||||||
|
newSpecies as unknown as EditDataType<SpeciesDetailsType>,
|
||||||
|
field as unknown as keyof EditDataType<SpeciesDetailsType>
|
||||||
|
)
|
||||||
|
const { error } = errorObject
|
||||||
|
if (error) errors.push(errorObject)
|
||||||
|
}
|
||||||
|
if (errors.length > 0) {
|
||||||
|
notify('Following validators failed: \n' + errors.map(e => `${e.name}: ${e.error}`).join('\n'), 'error')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const convertedSpecies = convertSpeciesTaxonomyFields(newSpecies)
|
||||||
|
const everyLs = editData.now_ls.map(ls => ls.com_species) as unknown as Editable<Species>[]
|
||||||
|
const filteredLs = everyLs.filter(species => species.rowState === 'new')
|
||||||
|
|
||||||
|
const taxonomyErrors = checkSpeciesTaxonomy(convertedSpecies, speciesData!.concat(filteredLs), [])
|
||||||
|
if (taxonomyErrors.size > 0) {
|
||||||
|
const errorMessage = [...taxonomyErrors].reduce((acc, currentError) => acc + `\n${currentError}`)
|
||||||
|
notify(errorMessage, 'error', null)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return convertedSpecies
|
||||||
|
}
|
||||||
|
|
||||||
const speciesColumns: MRT_ColumnDef<Species>[] = [
|
const speciesColumns: MRT_ColumnDef<Species>[] = [
|
||||||
{
|
{
|
||||||
@@ -80,6 +167,14 @@ export const SpeciesTab = () => {
|
|||||||
accessorKey: 'com_species.taxonomic_status',
|
accessorKey: 'com_species.taxonomic_status',
|
||||||
header: 'Taxon status',
|
header: 'Taxon status',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'com_species.sp_comment',
|
||||||
|
header: 'Comment',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'com_species.sp_author',
|
||||||
|
header: 'Author',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
const formFields: { name: string; label: string; required?: boolean }[] = [
|
const formFields: { name: string; label: string; required?: boolean }[] = [
|
||||||
{ name: 'order_name', label: 'Order', required: true },
|
{ name: 'order_name', label: 'Order', required: true },
|
||||||
@@ -88,26 +183,36 @@ export const SpeciesTab = () => {
|
|||||||
{ name: 'species_name', label: 'Species', required: true },
|
{ name: 'species_name', label: 'Species', required: true },
|
||||||
{ name: 'subclass_or_superorder_name', label: 'Subclass or Superorder' },
|
{ name: 'subclass_or_superorder_name', label: 'Subclass or Superorder' },
|
||||||
{ name: 'suborder_or_superfamily_name', label: 'Suborder or Superfamily' },
|
{ name: 'suborder_or_superfamily_name', label: 'Suborder or Superfamily' },
|
||||||
|
{ name: 'subfamily_name', label: 'Subfamily or Tribe' },
|
||||||
{ name: 'unique_identifier', label: 'Unique Identifier', required: true },
|
{ name: 'unique_identifier', label: 'Unique Identifier', required: true },
|
||||||
{ name: 'taxonomic_status', label: 'Taxon status' },
|
{ name: 'taxonomic_status', label: 'Taxon status' },
|
||||||
|
{ name: 'sp_comment', label: 'Comment' },
|
||||||
|
{ name: 'sp_author', label: 'Author' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if (!mode.read && !speciesData) return <CircularProgress />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grouped title="Species">
|
<Grouped title="Species">
|
||||||
{!mode.read && (
|
{!mode.read && (
|
||||||
<Box display="flex" gap={1}>
|
<Box display="flex" gap={1}>
|
||||||
<EditingForm<Species, LocalityDetailsType>
|
<EditingForm<EditDataType<Species>, LocalityDetailsType>
|
||||||
buttonText="Add new Species"
|
buttonText="Add new Species"
|
||||||
formFields={formFields}
|
formFields={formFields}
|
||||||
editAction={(newSpecies: Species) => {
|
existingObject={{ unique_identifier: '-' }}
|
||||||
|
replacedValues={replacedValues}
|
||||||
|
copyTaxonomyButton={copyTaxonomyButton}
|
||||||
|
editAction={(newSpecies: EditDataType<Species>) => {
|
||||||
|
const convertedSpecies = convertAndCheckNewSpeciesTaxonomy(newSpecies)
|
||||||
|
if (!convertedSpecies) return
|
||||||
setEditData({
|
setEditData({
|
||||||
...editData,
|
...editData,
|
||||||
now_ls: [
|
now_ls: [
|
||||||
...editData.now_ls,
|
...editData.now_ls,
|
||||||
{
|
{
|
||||||
lid: editData.lid,
|
lid: editData.lid,
|
||||||
species_id: newSpecies.species_id,
|
species_id: undefined,
|
||||||
com_species: { ...(newSpecies as unknown as SpeciesDetailsType) },
|
com_species: { ...(convertedSpecies as unknown as SpeciesDetailsType), class_name: 'Mammalia' },
|
||||||
rowState: 'new',
|
rowState: 'new',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -130,7 +235,9 @@ export const SpeciesTab = () => {
|
|||||||
{
|
{
|
||||||
lid: editData.lid,
|
lid: editData.lid,
|
||||||
species_id: newSpecies.species_id,
|
species_id: newSpecies.species_id,
|
||||||
com_species: { ...(newSpecies as unknown as SpeciesDetailsType) },
|
com_species: {
|
||||||
|
...(fixNullValuesInTaxonomyFields(newSpecies) as SpeciesDetailsType),
|
||||||
|
},
|
||||||
rowState: 'new',
|
rowState: 'new',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { validateSpecies } from '@/shared/validators/species'
|
|||||||
import { emptySpecies } from '../DetailView/common/defaultValues'
|
import { emptySpecies } from '../DetailView/common/defaultValues'
|
||||||
import { useNotify } from '@/hooks/notification'
|
import { useNotify } from '@/hooks/notification'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { fixNullValuesInTaxonomyFields } from '@/util/taxonomyUtilities'
|
||||||
|
|
||||||
export const SpeciesDetails = () => {
|
export const SpeciesDetails = () => {
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
@@ -40,15 +41,11 @@ export const SpeciesDetails = () => {
|
|||||||
}, [deleteSuccess, deleteError, notify, navigate])
|
}, [deleteSuccess, deleteError, notify, navigate])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// changes subclass, suborder, and subfamily from null to empty string to make validators work
|
// changes subclass, suborder, subfamily and taxonomic_status from null to empty string to make validators work
|
||||||
// this should be removed if validators are improved in the future
|
// this should be removed if validators are improved in the future
|
||||||
if (data) {
|
if (data) {
|
||||||
setModifiedData({
|
const fixedSpeciesData = fixNullValuesInTaxonomyFields(data)
|
||||||
...data,
|
setModifiedData(fixedSpeciesData as SpeciesDetailsType)
|
||||||
subclass_or_superorder_name: data.subclass_or_superorder_name ?? '',
|
|
||||||
suborder_or_superfamily_name: data.suborder_or_superfamily_name ?? '',
|
|
||||||
subfamily_name: data.subfamily_name ?? '',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}, [data])
|
}, [data])
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,66 @@ import { Grouped } from '@/components/DetailView/common/tabLayoutHelpers'
|
|||||||
import { MRT_ColumnDef } from 'material-react-table'
|
import { MRT_ColumnDef } from 'material-react-table'
|
||||||
import { EditableTable } from '@/components/DetailView/common/EditableTable'
|
import { EditableTable } from '@/components/DetailView/common/EditableTable'
|
||||||
import { EditingForm, EditingFormField } from '@/components/DetailView/common/EditingForm'
|
import { EditingForm, EditingFormField } from '@/components/DetailView/common/EditingForm'
|
||||||
|
import { useNotify } from '@/hooks/notification'
|
||||||
|
import { validateSynonym } from '@/shared/validators/synonym'
|
||||||
|
import { convertSynonymTaxonomyFields } from '@/util/taxonomyUtilities'
|
||||||
|
import { useGetAllSpeciesQuery } from '@/redux/speciesReducer'
|
||||||
|
import { skipToken } from '@reduxjs/toolkit/query'
|
||||||
|
import { CircularProgress } from '@mui/material'
|
||||||
|
|
||||||
export const SynonymTab = () => {
|
export const SynonymTab = () => {
|
||||||
const { mode, setEditData, editData } = useDetailContext<SpeciesDetailsType>()
|
const { mode, setEditData, editData } = useDetailContext<SpeciesDetailsType>()
|
||||||
|
const { data: speciesQueryData, isFetching } = useGetAllSpeciesQuery(mode.read ? skipToken : undefined)
|
||||||
|
const { notify } = useNotify()
|
||||||
|
|
||||||
|
const convertAndCheckNewSynonymTaxonomy = (newSynonym: EditDataType<SpeciesSynonym>) => {
|
||||||
|
const errors = []
|
||||||
|
for (const field in newSynonym) {
|
||||||
|
const errorObject = validateSynonym(
|
||||||
|
newSynonym as unknown as EditDataType<SpeciesSynonym>,
|
||||||
|
field as unknown as keyof EditDataType<SpeciesSynonym>
|
||||||
|
)
|
||||||
|
const { error } = errorObject
|
||||||
|
if (error) errors.push(errorObject)
|
||||||
|
}
|
||||||
|
if (errors.length > 0) {
|
||||||
|
notify('Following validators failed: \n' + errors.map(e => `${e.name}: ${e.error}`).join('\n'), 'error')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const convertedSynonym = convertSynonymTaxonomyFields(newSynonym)
|
||||||
|
for (const existingSynonym of editData.com_taxa_synonym) {
|
||||||
|
if (
|
||||||
|
convertedSynonym.syn_genus_name === existingSynonym.syn_genus_name &&
|
||||||
|
convertedSynonym.syn_species_name === existingSynonym.syn_species_name
|
||||||
|
) {
|
||||||
|
notify(
|
||||||
|
`${convertedSynonym.syn_genus_name} ${convertedSynonym.syn_species_name} \
|
||||||
|
has already been added as a synonym for this species.`,
|
||||||
|
'error',
|
||||||
|
null
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const existingSpecies of speciesQueryData!) {
|
||||||
|
if (
|
||||||
|
convertedSynonym.syn_genus_name === existingSpecies.genus_name &&
|
||||||
|
convertedSynonym.syn_species_name === existingSpecies.species_name
|
||||||
|
) {
|
||||||
|
notify(
|
||||||
|
`${convertedSynonym.syn_genus_name} ${convertedSynonym.syn_species_name} \
|
||||||
|
has already been created as a separate species, adding it as a synonym is currently not allowed.`,
|
||||||
|
'error',
|
||||||
|
null
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertedSynonym
|
||||||
|
}
|
||||||
|
|
||||||
const columns: MRT_ColumnDef<SpeciesSynonym>[] = [
|
const columns: MRT_ColumnDef<SpeciesSynonym>[] = [
|
||||||
{
|
{
|
||||||
@@ -31,15 +88,17 @@ export const SynonymTab = () => {
|
|||||||
|
|
||||||
const editingForm = (
|
const editingForm = (
|
||||||
<EditingForm<Species, SpeciesDetailsType>
|
<EditingForm<Species, SpeciesDetailsType>
|
||||||
buttonText="Add new Species"
|
buttonText="Add synonym"
|
||||||
formFields={formFields}
|
formFields={formFields}
|
||||||
editAction={(newSynonym: EditDataType<SpeciesSynonym>) => {
|
editAction={(newSynonym: EditDataType<SpeciesSynonym>) => {
|
||||||
|
const convertedSynonym = convertAndCheckNewSynonymTaxonomy(newSynonym)
|
||||||
|
if (!convertedSynonym) return
|
||||||
setEditData({
|
setEditData({
|
||||||
...editData,
|
...editData,
|
||||||
com_taxa_synonym: [
|
com_taxa_synonym: [
|
||||||
...editData.com_taxa_synonym,
|
...editData.com_taxa_synonym,
|
||||||
{
|
{
|
||||||
...newSynonym,
|
...convertedSynonym,
|
||||||
rowState: 'new',
|
rowState: 'new',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -48,6 +107,8 @@ export const SynonymTab = () => {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (isFetching) return <CircularProgress />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Grouped title="Synonyms">
|
<Grouped title="Synonyms">
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { SpeciesDetailsType, Species } from '@/shared/types'
|
import { SpeciesDetailsType, Species } from '@/shared/types'
|
||||||
import { ArrayFrame, HalfFrames } from '@/components/DetailView/common/tabLayoutHelpers'
|
import { ArrayFrame, HalfFrames } from '@/components/DetailView/common/tabLayoutHelpers'
|
||||||
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
||||||
import { emptyOption } from '@/components/DetailView/common/misc'
|
import { fixNullValuesInTaxonomyFields } from '@/util/taxonomyUtilities'
|
||||||
import { Box } from '@mui/material'
|
import { Box } from '@mui/material'
|
||||||
import { SelectingTable } from '@/components/DetailView/common/SelectingTable'
|
import { SelectingTable } from '@/components/DetailView/common/SelectingTable'
|
||||||
import { useGetAllSpeciesQuery } from '@/redux/speciesReducer'
|
import { useGetAllSpeciesQuery } from '@/redux/speciesReducer'
|
||||||
import { smallSpeciesTableColumns } from '@/common'
|
import { smallSpeciesTableColumns } from '@/common'
|
||||||
import { SynonymsModal } from '../SynonymsModal'
|
import { SynonymsModal } from '../SynonymsModal'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import { taxonStatusOptions } from '@/shared/taxonStatusOptions'
|
||||||
|
|
||||||
export const TaxonomyTab = () => {
|
export const TaxonomyTab = () => {
|
||||||
const { textField, dropdown, bigTextField, editData, setEditData, mode } = useDetailContext<SpeciesDetailsType>()
|
const { textField, dropdown, bigTextField, editData, setEditData, mode } = useDetailContext<SpeciesDetailsType>()
|
||||||
@@ -21,8 +22,9 @@ export const TaxonomyTab = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const copyTaxonomyButton = (
|
const copyTaxonomyButton = (
|
||||||
<Box key="copy_existing_taxonomy_button" id="copy_existing_taxonomy_button">
|
<Box key="copy_existing_taxonomy_button">
|
||||||
<SelectingTable<Species, Species>
|
<SelectingTable<Species, Species>
|
||||||
|
dataCy="copy_existing_taxonomy_button"
|
||||||
buttonText="Copy existing taxonomy"
|
buttonText="Copy existing taxonomy"
|
||||||
data={speciesQueryData}
|
data={speciesQueryData}
|
||||||
title="Species"
|
title="Species"
|
||||||
@@ -33,16 +35,17 @@ export const TaxonomyTab = () => {
|
|||||||
useObject={true}
|
useObject={true}
|
||||||
tableRowAction={handleRowActionClick}
|
tableRowAction={handleRowActionClick}
|
||||||
editingAction={(selectedSpecies: Species) => {
|
editingAction={(selectedSpecies: Species) => {
|
||||||
|
const fixedSpecies = fixNullValuesInTaxonomyFields(selectedSpecies)
|
||||||
setEditData({
|
setEditData({
|
||||||
...editData,
|
...editData,
|
||||||
subclass_or_superorder_name: selectedSpecies.subclass_or_superorder_name ?? '',
|
subclass_or_superorder_name: fixedSpecies.subclass_or_superorder_name,
|
||||||
order_name: selectedSpecies.order_name ?? '',
|
order_name: fixedSpecies.order_name!,
|
||||||
suborder_or_superfamily_name: selectedSpecies.suborder_or_superfamily_name ?? '',
|
suborder_or_superfamily_name: fixedSpecies.suborder_or_superfamily_name,
|
||||||
family_name: selectedSpecies.family_name ?? '',
|
family_name: fixedSpecies.family_name!,
|
||||||
subfamily_name: selectedSpecies.subfamily_name ?? '',
|
subfamily_name: fixedSpecies.subfamily_name,
|
||||||
genus_name: selectedSpecies.genus_name ?? '',
|
genus_name: fixedSpecies.genus_name!,
|
||||||
species_name: selectedSpecies.species_name ?? '',
|
species_name: fixedSpecies.species_name!,
|
||||||
unique_identifier: selectedSpecies.unique_identifier ?? '',
|
unique_identifier: fixedSpecies.unique_identifier!,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -50,16 +53,6 @@ export const TaxonomyTab = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
|
||||||
const taxonStatusOptions = [
|
|
||||||
emptyOption,
|
|
||||||
'family attrib of genus uncertain',
|
|
||||||
'genus attrib of species uncertain',
|
|
||||||
'informal species',
|
|
||||||
'species validity uncertain',
|
|
||||||
'taxonomic validity uncertain',
|
|
||||||
'NOW synonym',
|
|
||||||
]
|
|
||||||
|
|
||||||
const classification = [
|
const classification = [
|
||||||
[
|
[
|
||||||
'Class',
|
'Class',
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export const api = createApi({
|
|||||||
'localities',
|
'localities',
|
||||||
'species',
|
'species',
|
||||||
'specieslist',
|
'specieslist',
|
||||||
|
'speciessynonyms',
|
||||||
'reference',
|
'reference',
|
||||||
'references',
|
'references',
|
||||||
'timeunits',
|
'timeunits',
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ const localitiesApi = api.injectEndpoints({
|
|||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: { locality },
|
body: { locality },
|
||||||
}),
|
}),
|
||||||
invalidatesTags: (result, _error, { lid }) => (result ? [{ type: 'locality', id: lid }, 'localities'] : []),
|
invalidatesTags: (result, _error, { lid }) =>
|
||||||
|
result ? [{ type: 'locality', id: lid }, 'localities', 'specieslist'] : [],
|
||||||
}),
|
}),
|
||||||
deleteLocality: builder.mutation<void, number>({
|
deleteLocality: builder.mutation<void, number>({
|
||||||
query: id => ({
|
query: id => ({
|
||||||
|
|||||||
@@ -7,18 +7,19 @@ const speciesApi = api.injectEndpoints({
|
|||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/species/all`,
|
url: `/species/all`,
|
||||||
}),
|
}),
|
||||||
providesTags: result => (result ? [{ type: 'specieslist' }] : []),
|
providesTags: result => (result ? [{ type: 'specieslist' }, 'speciessynonyms'] : []),
|
||||||
}),
|
}),
|
||||||
getAllSynonyms: builder.query<SpeciesSynonym[], void>({
|
getAllSynonyms: builder.query<SpeciesSynonym[], void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/species/synonyms`,
|
url: `/species/synonyms`,
|
||||||
}),
|
}),
|
||||||
|
providesTags: result => (result ? ['speciessynonyms'] : []),
|
||||||
}),
|
}),
|
||||||
getSpeciesDetails: builder.query<SpeciesDetailsType, string>({
|
getSpeciesDetails: builder.query<SpeciesDetailsType, string>({
|
||||||
query: id => ({
|
query: id => ({
|
||||||
url: `/species/${id}`,
|
url: `/species/${id}`,
|
||||||
}),
|
}),
|
||||||
providesTags: result => (result ? [{ type: 'species', id: result.species_id }] : []),
|
providesTags: result => (result ? [{ type: 'species', id: result.species_id }, 'speciessynonyms'] : []),
|
||||||
}),
|
}),
|
||||||
editSpecies: builder.mutation<SpeciesDetailsType, EditDataType<SpeciesDetailsType>>({
|
editSpecies: builder.mutation<SpeciesDetailsType, EditDataType<SpeciesDetailsType>>({
|
||||||
query: species => ({
|
query: species => ({
|
||||||
@@ -27,7 +28,7 @@ const speciesApi = api.injectEndpoints({
|
|||||||
body: { species },
|
body: { species },
|
||||||
}),
|
}),
|
||||||
invalidatesTags: (result, _error, { species_id }) =>
|
invalidatesTags: (result, _error, { species_id }) =>
|
||||||
result ? [{ type: 'species', id: species_id }, 'specieslist'] : [],
|
result ? [{ type: 'species', id: species_id }, 'specieslist', 'speciessynonyms'] : [],
|
||||||
}),
|
}),
|
||||||
deleteSpecies: builder.mutation<void, number>({
|
deleteSpecies: builder.mutation<void, number>({
|
||||||
query: id => ({
|
query: id => ({
|
||||||
@@ -36,15 +37,14 @@ const speciesApi = api.injectEndpoints({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
invalidatesTags: (result, _error, species_id) =>
|
invalidatesTags: (result, _error, species_id) =>
|
||||||
typeof result !== 'undefined' ? [{ type: 'species', id: species_id }, 'specieslist'] : [],
|
typeof result !== 'undefined' ? [{ type: 'species', id: species_id }, 'specieslist', 'speciessynonyms'] : [],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
useGetAllSpeciesQuery,
|
useGetAllSpeciesQuery,
|
||||||
useLazyGetAllSpeciesQuery,
|
useGetAllSynonymsQuery,
|
||||||
useLazyGetAllSynonymsQuery,
|
|
||||||
useGetSpeciesDetailsQuery,
|
useGetSpeciesDetailsQuery,
|
||||||
useEditSpeciesMutation,
|
useEditSpeciesMutation,
|
||||||
useDeleteSpeciesMutation,
|
useDeleteSpeciesMutation,
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// cannot be imported from DetailView -> misc since files in shared folder cannot import from elsewhere in frontend
|
||||||
|
const emptyOption = {
|
||||||
|
optionDisplay: 'No value',
|
||||||
|
display: '',
|
||||||
|
value: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const taxonStatusOptions = [
|
||||||
|
emptyOption,
|
||||||
|
'family attrib of genus uncertain',
|
||||||
|
'genus attrib of species uncertain',
|
||||||
|
'informal species',
|
||||||
|
'species validity uncertain',
|
||||||
|
'taxonomic validity uncertain',
|
||||||
|
'NOW synonym',
|
||||||
|
]
|
||||||
@@ -332,6 +332,7 @@ export type Species = {
|
|||||||
locomo2: string | null
|
locomo2: string | null
|
||||||
locomo3: string | null
|
locomo3: string | null
|
||||||
sp_comment: string | null
|
sp_comment: string | null
|
||||||
|
sp_author: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RegionDetails = Prisma.now_reg_coord & { now_reg_coord_people: Array<RegionCoordinator> } & {
|
export type RegionDetails = Prisma.now_reg_coord & { now_reg_coord_people: Array<RegionCoordinator> } & {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { taxonStatusOptions } from '../taxonStatusOptions'
|
||||||
import { EditDataType, SpeciesDetailsType } from '../types'
|
import { EditDataType, SpeciesDetailsType } from '../types'
|
||||||
import { Validators, validator } from './validator'
|
import { Validators, validator } from './validator'
|
||||||
|
|
||||||
@@ -80,6 +81,7 @@ export const validateSpecies = (
|
|||||||
name: 'Species',
|
name: 'Species',
|
||||||
required: true,
|
required: true,
|
||||||
asString: (speciesName: string) => {
|
asString: (speciesName: string) => {
|
||||||
|
if (speciesName.indexOf(' ') !== -1) return 'Species name must not contain any spaces.'
|
||||||
if (speciesName !== 'indet.' && editData.genus_name === 'indet.')
|
if (speciesName !== 'indet.' && editData.genus_name === 'indet.')
|
||||||
return 'when the Genus is indet., Species must also be indet.'
|
return 'when the Genus is indet., Species must also be indet.'
|
||||||
if (speciesName !== 'sp.' && editData.genus_name === 'gen.')
|
if (speciesName !== 'sp.' && editData.genus_name === 'gen.')
|
||||||
@@ -89,6 +91,14 @@ export const validateSpecies = (
|
|||||||
return
|
return
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
taxonomic_status: {
|
||||||
|
name: 'Taxonomic Status',
|
||||||
|
asString: (taxonomicStatus: string) => {
|
||||||
|
if (!taxonStatusOptions.slice(1).includes(taxonomicStatus) && taxonomicStatus !== '')
|
||||||
|
return `Taxonomic Status must be one of the following (or left empty): ${taxonStatusOptions.slice(1).join(', ')}.`
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
unique_identifier: {
|
unique_identifier: {
|
||||||
name: 'Unique Identifier',
|
name: 'Unique Identifier',
|
||||||
required: true,
|
required: true,
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { EditDataType, SpeciesSynonym } from '../types'
|
||||||
|
import { Validators, validator } from './validator'
|
||||||
|
|
||||||
|
export const validateSynonym = (
|
||||||
|
editData: EditDataType<SpeciesSynonym>,
|
||||||
|
fieldName: keyof EditDataType<SpeciesSynonym>
|
||||||
|
) => {
|
||||||
|
const validators: Validators<Partial<EditDataType<SpeciesSynonym>>> = {
|
||||||
|
syn_genus_name: {
|
||||||
|
name: 'Synonym genus name',
|
||||||
|
required: true,
|
||||||
|
asString: (synGenusName: string) => {
|
||||||
|
if (synGenusName.indexOf(' ') !== -1) return 'Genus must not contain any spaces.'
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
syn_species_name: {
|
||||||
|
name: 'Synonym species name',
|
||||||
|
required: true,
|
||||||
|
asString: (synSpeciesName: string) => {
|
||||||
|
if (synSpeciesName !== 'indet.' && editData.syn_genus_name === 'indet.')
|
||||||
|
return 'when the Genus is indet., Species must also be indet.'
|
||||||
|
if (synSpeciesName !== 'sp.' && editData.syn_genus_name === 'gen.')
|
||||||
|
return 'when the Genus is gen., Species must be sp.'
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return validator<EditDataType<SpeciesSynonym>>(validators, editData, fieldName)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { EditDataType, Species, SpeciesSynonym } from '@/shared/types'
|
import { EditDataType, Species, SpeciesDetailsType, SpeciesSynonym } from '@/shared/types'
|
||||||
|
|
||||||
const generateMultipleParentsError = (
|
const generateMultipleParentsError = (
|
||||||
invalidField: string,
|
invalidField: string,
|
||||||
@@ -11,7 +11,10 @@ Please contact the NOW administration to fix this taxonomy.`
|
|||||||
|
|
||||||
const isDuplicateTaxon = (newSpecies: EditDataType<Species>, existingSpecies: Species) => {
|
const isDuplicateTaxon = (newSpecies: EditDataType<Species>, existingSpecies: Species) => {
|
||||||
if (
|
if (
|
||||||
newSpecies.species_id !== existingSpecies.species_id &&
|
// the check for undefined species_id is here to make sure you cannot add two new,
|
||||||
|
// identical species at the same time (e.g. in Locality -> Species -> Add new species)
|
||||||
|
((newSpecies.species_id === undefined && existingSpecies.species_id === undefined) ||
|
||||||
|
newSpecies.species_id !== existingSpecies.species_id) &&
|
||||||
newSpecies.genus_name === existingSpecies.genus_name &&
|
newSpecies.genus_name === existingSpecies.genus_name &&
|
||||||
newSpecies.species_name === existingSpecies.species_name &&
|
newSpecies.species_name === existingSpecies.species_name &&
|
||||||
newSpecies.unique_identifier === existingSpecies.unique_identifier
|
newSpecies.unique_identifier === existingSpecies.unique_identifier
|
||||||
@@ -133,7 +136,7 @@ const checkSubFamilyGenus = (newSpecies: EditDataType<Species>, existingSpecies:
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const checkTaxonomy = (
|
export const checkSpeciesTaxonomy = (
|
||||||
newSpecies: EditDataType<Species>,
|
newSpecies: EditDataType<Species>,
|
||||||
existingSpeciesArray: Species[],
|
existingSpeciesArray: Species[],
|
||||||
synonyms: SpeciesSynonym[]
|
synonyms: SpeciesSynonym[]
|
||||||
@@ -314,7 +317,7 @@ const convertTaxonomyField = (value: string | null | undefined) => {
|
|||||||
return convertedValue
|
return convertedValue
|
||||||
}
|
}
|
||||||
|
|
||||||
export const convertTaxonomyFields = (species: EditDataType<Species>) => {
|
export const convertSpeciesTaxonomyFields = (species: EditDataType<Species>) => {
|
||||||
const speciesName = species.species_name
|
const speciesName = species.species_name
|
||||||
let lowercasedSpeciesName = ''
|
let lowercasedSpeciesName = ''
|
||||||
if (speciesName) {
|
if (speciesName) {
|
||||||
@@ -336,3 +339,31 @@ export const convertTaxonomyFields = (species: EditDataType<Species>) => {
|
|||||||
}
|
}
|
||||||
return convertedSpecies as EditDataType<Species>
|
return convertedSpecies as EditDataType<Species>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fixNullValuesInTaxonomyFields = (species: Species | SpeciesDetailsType) => {
|
||||||
|
return {
|
||||||
|
...species,
|
||||||
|
subclass_or_superorder_name: species.subclass_or_superorder_name ?? '',
|
||||||
|
suborder_or_superfamily_name: species.suborder_or_superfamily_name ?? '',
|
||||||
|
subfamily_name: species.subfamily_name ?? '',
|
||||||
|
taxonomic_status: species.taxonomic_status ?? '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const convertSynonymTaxonomyFields = (synonym: EditDataType<SpeciesSynonym>) => {
|
||||||
|
const synSpeciesName = synonym.syn_species_name
|
||||||
|
let lowercasedSynSpeciesName = ''
|
||||||
|
if (synSpeciesName) {
|
||||||
|
if (synSpeciesName !== 'indet.') {
|
||||||
|
lowercasedSynSpeciesName = synSpeciesName.toLowerCase()
|
||||||
|
} else {
|
||||||
|
lowercasedSynSpeciesName = synSpeciesName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const convertedSynonym = {
|
||||||
|
...synonym,
|
||||||
|
syn_genus_name: convertTaxonomyField(synonym.syn_genus_name),
|
||||||
|
syn_species_name: lowercasedSynSpeciesName,
|
||||||
|
}
|
||||||
|
return convertedSynonym as EditDataType<SpeciesSynonym>
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user