Merge pull request #922 from nowcommunity/fix-museum-issues

Fix museum related issues and return to table button issues
This commit is contained in:
Kari Lintulaakso
2025-09-01 12:17:07 +03:00
committed by GitHub
12 changed files with 53 additions and 77 deletions
+1 -5
View File
@@ -32,13 +32,9 @@ describe('Creating new museum works', () => {
})
it('Contains correct data', () => {
const { museum: museumId, institution, used_morph, used_now, used_gene } = createdMuseum!
const { museum: museumId, institution } = createdMuseum!
expect(museumId).toBeDefined()
expect(institution).toEqual('Australian Museum') // 'Institution name is different'
expect(used_morph).toEqual(true)
// fixRadioSelection converts null values into false
expect(used_now).toEqual(false)
expect(used_gene).toEqual(false)
})
it('Creation fails with empty museum code', async () => {
-6
View File
@@ -8,9 +8,6 @@ export const newMuseumBasis: Museum = {
state_code: '',
state: '',
country: 'Australia',
used_morph: true,
used_now: null,
used_gene: null,
}
export const editedMuseum: Museum = {
@@ -21,7 +18,4 @@ export const editedMuseum: Museum = {
state_code: 'NSW',
state: 'New South Wales',
country: 'Australia',
used_morph: false,
used_now: true,
used_gene: null,
}
+1 -22
View File
@@ -32,32 +32,11 @@ describe('Updating museum works', () => {
})
it('Contains correct data', () => {
const { museum, city, state, state_code, used_morph, used_now, used_gene } = updatedMuseum!
const { museum, city, state, state_code } = updatedMuseum!
expect(museum).toEqual('AM')
expect(city).toEqual('Canberra')
expect(state).toEqual('New South Wales')
expect(state_code).toEqual('NSW')
expect(used_morph).toEqual(false)
expect(used_now).toEqual(true)
expect(used_gene).toEqual(false) // fixRadioSelection converts null values into false
})
it('Updating succeeds with string values for used_fields', async () => {
const { body: resultBody, status: putReqStatus } = await send<{ museum: string }>('museum/', 'PUT', {
museum: { ...editedMuseum, used_morph: 'true', used_now: 'true', used_gene: 'true' },
})
const { museum: updatedId } = resultBody
expect(typeof updatedId).toEqual('string') // `Invalid result returned on write: ${createdId}`
expect(putReqStatus).toEqual(200)
const { body: getReqBody, status: getReqStat } = await send<Museum>(`museum/${updatedId}`, 'GET')
expect(getReqStat).toEqual(200)
const { used_morph, used_now, used_gene } = getReqBody
expect(used_morph).toEqual(true)
expect(used_now).toEqual(true)
expect(used_gene).toEqual(true)
})
it('Updating fails with empty institution', async () => {
@@ -1,5 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useNavigate } from 'react-router-dom'
import { useLocation, useNavigate } from 'react-router-dom'
import { Button, Box, Typography, CircularProgress, Divider, alpha, List, ListItemText } from '@mui/material'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
import SaveIcon from '@mui/icons-material/Save'
@@ -258,6 +258,7 @@ export const ReturnButton = () => {
const navigate = useNavigate()
const { setPreviousTableUrls, previousTableUrls } = usePageContext()
const { mode, setMode } = useDetailContext()
const location = useLocation()
if (mode.staging) {
return (
@@ -282,6 +283,10 @@ export const ReturnButton = () => {
newUrls.splice(-1)
setPreviousTableUrls(newUrls)
navigate(previousTableUrl, { relative: 'path' })
} else {
// this should only happen if the user navigates to e.g. a detail view directly with an url,
// instead of using link in the app
navigate(location.pathname.substring(0, location.pathname.indexOf('/', 1)), { relative: 'path' })
}
}}
>
@@ -57,6 +57,8 @@ export const MuseumTab = () => {
<EditableTable<Editable<Museum>, LocalityDetailsType>
columns={columns.map(col => ({ ...col, accessorKey: `com_mlist.${col.accessorKey}` }))}
field="now_mus"
idFieldName="museum"
url="museum"
/>
</Grouped>
)
@@ -16,7 +16,7 @@ export const MuseumDetails = () => {
skip: isNew,
})
const [editMuseumRequest, { isLoading: mutationLoading }] = useEditMuseumMutation()
const notify = useNotify()
const { notify } = useNotify()
const navigate = useNavigate()
const tabs: TabType[] = [
@@ -55,7 +55,6 @@ export const MuseumDetails = () => {
isNew={isNew}
validator={validateMuseum}
deleteFunction={undefined}
hasStagingMode
/>
)
}
@@ -23,12 +23,16 @@ export const LocalityTab = ({ isNew }: { isNew: boolean }) => {
header: 'Min Age',
},
]
if (isNew)
if (isNew) {
return (
<div>
Link localities to this museum after finalizing it by editing a locality and navigating to the museum tab there.
</div>
)
} else if (data.localities.length === 0) {
return <div>Link localities to this museum by editing a locality and navigating to the museum tab there.</div>
}
return <SimpleTable columns={columns} data={data.localities} idFieldName="lid" url="locality" />
}
@@ -1,10 +1,25 @@
import { ArrayFrame } from '@/components/DetailView/common/tabLayoutHelpers'
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
import { modeOptionToMode, useDetailContext } from '@/components/DetailView/Context/DetailContext'
import { useNotify } from '@/hooks/notification'
import { Museum } from '@/shared/types'
import { validCountries } from '@/shared/validators/countryList'
import { useEffect } from 'react'
export const MuseumInfoTab = ({ isNew }: { isNew?: boolean }) => {
const { textField, radioSelection, dropdownWithSearch } = useDetailContext<Museum>()
const { textField, dropdownWithSearch, mode } = useDetailContext<Museum>()
const { notify } = useNotify()
useEffect(() => {
if (mode === modeOptionToMode['new']) {
notify(
"Due to current limitations, using an existing museum's code will overwrite that museum with the one you are currently creating. \n \
Check that you are using a unique museum code.",
'warning',
null
)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [mode])
const countryOptions = ['', ...validCountries]
@@ -15,40 +30,7 @@ export const MuseumInfoTab = ({ isNew }: { isNew?: boolean }) => {
['Country', dropdownWithSearch('country', countryOptions, 'Country')],
['State', textField('state')],
['State code', textField('state_code')],
[
'Used morph',
radioSelection(
'used_morph',
[
{ value: 'null', display: 'No' },
{ value: 'true', display: 'Yes' },
],
'used-morph'
),
],
[
'Used now',
radioSelection(
'used_now',
[
{ value: 'null', display: 'No' },
{ value: 'true', display: 'Yes' },
],
'used-now'
),
],
[
'Used gene',
radioSelection(
'used_gene',
[
{ value: 'null', display: 'No' },
{ value: 'true', display: 'Yes' },
],
'used-gene'
),
],
['Museum code', textField('museum', { type: 'text', readonly: !isNew })],
['Museum code', textField('museum', { type: 'text', readonly: !isNew, trim: true })],
]
return (
+1 -1
View File
@@ -47,7 +47,7 @@ export const PageContextProvider = <T extends object>({
editRights: EditRights
}) => {
const [idList, setIdList] = useState<string[]>([])
const [previousTableUrls, setPreviousTableUrls] = useState<string[]>([`/${viewName}`])
const [previousTableUrls, setPreviousTableUrls] = useState<string[]>([])
// TODO: replace with some default values from variables
const [sqlLimit, setSqlLimit] = useState<number>(defaultPagination.pageSize)
const [sqlOffset, setSqlOffset] = useState<number>(0)
@@ -5,9 +5,10 @@ import { ContactForm } from '../DetailView/common/ContactForm'
import FileDownloadIcon from '@mui/icons-material/FileDownload'
import '../../styles/TableToolBar.css'
import { useState } from 'react'
import { Link } from 'react-router-dom'
import { Link, useLocation } from 'react-router-dom'
import AddCircleIcon from '@mui/icons-material/AddCircle'
import { CrossSearchExportMenuItem } from '../CrossSearch/CrossSearchExportMenuItem'
import { usePageContext } from '../Page'
export const TableToolBar = <T extends MRT_RowData>({
table,
@@ -28,6 +29,8 @@ export const TableToolBar = <T extends MRT_RowData>({
selectorFn?: (id: T) => void
showNewButton?: boolean
}) => {
const { previousTableUrls, setPreviousTableUrls } = usePageContext<T>()
const location = useLocation()
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
const open = Boolean(anchorEl)
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
@@ -44,7 +47,14 @@ export const TableToolBar = <T extends MRT_RowData>({
<ContactForm<T> buttonText="Contact" noContext={true} />
{showNewButton && (
<Button variant="outlined" component={Link} to="new" className="button" startIcon={<AddCircleIcon />}>
<Button
variant="outlined"
component={Link}
to="new"
className="button"
startIcon={<AddCircleIcon />}
onClick={() => setPreviousTableUrls([...previousTableUrls, `${location.pathname}`])}
>
New
</Button>
)}
+1 -1
View File
@@ -23,7 +23,7 @@ export type LocalitySpeciesDetailsType = FixBigInt<Prisma.now_ls> & { com_specie
export type SpeciesLocality = FixBigInt<Prisma.now_ls> & { now_loc: Prisma.now_loc }
export type LocalityUpdate = Prisma.now_lau & { now_lr: LocalityReference[] } & { updates: UpdateLog[] }
export type SpeciesUpdate = Prisma.now_sau & { now_sr: SpeciesReference[] } & { updates: UpdateLog[] }
export type Museum = Prisma.com_mlist
export type Museum = Omit<Prisma.com_mlist, 'used_morph' | 'used_now' | 'used_gene'>
export type MuseumLocalities = Prisma.com_mlist & { localities: Prisma.now_loc[] }
export type PersonDetailsType = Prisma.com_people & { user: Omit<Prisma.com_users, 'password, newpassword'> | null } & {
now_user_group: string
+5
View File
@@ -19,6 +19,11 @@ export const validateMuseum = (editData: EditDataType<Museum>, fieldName: keyof
museum: {
name: 'Museum',
required: true,
asString: museumCode => {
if (museumCode.indexOf(' ') !== -1) return 'Museum code must not contain a space'
if (museumCode.toUpperCase() !== museumCode) return 'Museum code must only contains uppercase characters'
return null
},
},
institution: {
name: 'Institution',