mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Render display labels for sequence selection
This commit is contained in:
@@ -347,18 +347,32 @@ export const FieldWithTableSelection = <T extends object, ParentType extends obj
|
||||
sourceField,
|
||||
selectorTable,
|
||||
disabled,
|
||||
displayValue,
|
||||
getDisplayValue,
|
||||
}: {
|
||||
targetField: keyof ParentType
|
||||
sourceField: keyof T
|
||||
selectorTable: ReactElement
|
||||
disabled?: boolean
|
||||
displayValue?: string | number | null
|
||||
getDisplayValue?: (selected: T) => string | number | null | undefined
|
||||
}) => {
|
||||
const { editData, setEditData, validator, fieldsWithErrors, setFieldsWithErrors } = useDetailContext<ParentType>()
|
||||
const errorObject = validator(editData, targetField as keyof EditDataType<ParentType>)
|
||||
const { error } = errorObject
|
||||
const [open, setOpen] = useState(false)
|
||||
const [selectedDisplayValue, setSelectedDisplayValue] = useState<string | number | null | undefined>(displayValue)
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedDisplayValue(displayValue)
|
||||
}, [displayValue])
|
||||
|
||||
const selectorFn = (selected: T) => {
|
||||
setEditData({ ...editData, [targetField]: selected[sourceField] })
|
||||
const newDisplayValue = getDisplayValue ? getDisplayValue(selected) : selected[sourceField]
|
||||
setSelectedDisplayValue(
|
||||
typeof newDisplayValue === 'string' || typeof newDisplayValue === 'number' ? newDisplayValue : null
|
||||
)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
@@ -392,7 +406,7 @@ export const FieldWithTableSelection = <T extends object, ParentType extends obj
|
||||
size="small"
|
||||
error={!!error}
|
||||
helperText={error ?? ''}
|
||||
value={editData[targetField as keyof EditDataType<ParentType>] ?? undefined}
|
||||
value={selectedDisplayValue ?? editData[targetField as keyof EditDataType<ParentType>] ?? undefined}
|
||||
onClick={() => setOpen(true)}
|
||||
disabled={disabled}
|
||||
sx={{ backgroundColor: disabled ? 'grey' : '' }}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import { describe, expect, it } from '@jest/globals'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { DetailContext, DetailContextType, modeOptionToMode } from '@/components/DetailView/Context/DetailContext'
|
||||
import { SequenceSelect } from './SequenceSelect'
|
||||
import { TimeUnitDetailsType } from '@/shared/types'
|
||||
import { ReactNode } from 'react'
|
||||
import '@testing-library/jest-dom'
|
||||
|
||||
jest.mock('./SequenceTable', () => ({
|
||||
SequenceTable: ({
|
||||
selectorFn,
|
||||
}: {
|
||||
selectorFn?: (sequence: { sequence: number; display_value?: string }) => void
|
||||
}) => (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
selectorFn?.({
|
||||
sequence: 2,
|
||||
display_value: 'Updated Sequence Display',
|
||||
})
|
||||
}
|
||||
>
|
||||
open selector
|
||||
</button>
|
||||
),
|
||||
}))
|
||||
|
||||
type ContextWrapperProps = {
|
||||
children: ReactNode
|
||||
data?: Partial<TimeUnitDetailsType>
|
||||
}
|
||||
|
||||
const renderWithContext = ({ children, data }: ContextWrapperProps) => {
|
||||
const timeUnit = {
|
||||
sequence: 1,
|
||||
tu_name: 'TU-1',
|
||||
tu_display_name: 'TU display',
|
||||
rank: 'Age',
|
||||
low_bnd: 0,
|
||||
up_bnd: 0,
|
||||
now_tu_sequence: {
|
||||
sequence: 1,
|
||||
seq_name: 'Central Paratethys',
|
||||
},
|
||||
now_tau: [],
|
||||
low_bound: {
|
||||
bid: 1,
|
||||
b_name: 'low',
|
||||
age: 1,
|
||||
b_comment: '',
|
||||
},
|
||||
up_bound: {
|
||||
bid: 2,
|
||||
b_name: 'up',
|
||||
age: 2,
|
||||
b_comment: '',
|
||||
},
|
||||
...data,
|
||||
} as unknown as TimeUnitDetailsType
|
||||
|
||||
const contextValue: DetailContextType<TimeUnitDetailsType> = {
|
||||
data: timeUnit,
|
||||
mode: modeOptionToMode.edit,
|
||||
setMode: () => undefined,
|
||||
editData: timeUnit,
|
||||
setEditData: () => undefined,
|
||||
textField: () => <></>,
|
||||
bigTextField: () => <></>,
|
||||
dropdown: () => <></>,
|
||||
dropdownWithSearch: () => <></>,
|
||||
radioSelection: () => <></>,
|
||||
validator: (_editData, fieldName) => ({ name: String(fieldName), error: null }),
|
||||
fieldsWithErrors: {},
|
||||
setFieldsWithErrors: () => undefined,
|
||||
}
|
||||
|
||||
return render(
|
||||
<DetailContext.Provider value={contextValue as DetailContextType<unknown>}>{children}</DetailContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('SequenceSelect', () => {
|
||||
it('shows display label in edit mode when sequence has a name', () => {
|
||||
renderWithContext({ children: <SequenceSelect /> })
|
||||
|
||||
expect(screen.getByDisplayValue('Central Paratethys')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('updates display label when a new sequence is selected', async () => {
|
||||
const user = userEvent.setup()
|
||||
renderWithContext({ children: <SequenceSelect /> })
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /open selector/i }))
|
||||
|
||||
expect(screen.getByDisplayValue('Updated Sequence Display')).toBeTruthy()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,21 @@
|
||||
import { FieldWithTableSelection } from '@/components/DetailView/common/editingComponents'
|
||||
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
||||
import { SequenceDetailsType, TimeUnitDetailsType } from '@/shared/types'
|
||||
import { SequenceTable } from './SequenceTable'
|
||||
|
||||
export const SequenceSelect = () => {
|
||||
const { data } = useDetailContext<TimeUnitDetailsType>()
|
||||
|
||||
const displayValue = data.now_tu_sequence?.seq_name ?? ''
|
||||
|
||||
return (
|
||||
<FieldWithTableSelection<SequenceDetailsType & { display_value?: string }, TimeUnitDetailsType>
|
||||
key="sequence"
|
||||
sourceField="sequence"
|
||||
targetField="sequence"
|
||||
selectorTable={<SequenceTable />}
|
||||
displayValue={displayValue}
|
||||
getDisplayValue={sequence => sequence.display_value ?? sequence.seq_name ?? ''}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { SequenceDetailsType, TimeBound, TimeUnitDetailsType } from '@/shared/types'
|
||||
import { FieldWithTableSelection, TimeBoundSelection } from '@/components/DetailView/common/editingComponents'
|
||||
import { TimeBound, TimeUnitDetailsType } from '@/shared/types'
|
||||
import { TimeBoundSelection } from '@/components/DetailView/common/editingComponents'
|
||||
import { emptyOption } from '@/components/DetailView/common/misc'
|
||||
import { ArrayFrame, Grouped } from '@/components/DetailView/common/tabLayoutHelpers'
|
||||
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
||||
import { SequenceTable } from '@/components/Sequence/SequenceTable'
|
||||
import { Box } from '@mui/material'
|
||||
import { EditingForm, EditingFormField } from '@/components/DetailView/common/EditingForm'
|
||||
import { SequenceSelect } from '@/components/Sequence/SequenceSelect'
|
||||
|
||||
export const TimeUnitTab = () => {
|
||||
const { textField, dropdown, data, editData, setEditData, fieldsWithErrors, mode } =
|
||||
@@ -28,15 +28,7 @@ export const TimeUnitTab = () => {
|
||||
const timeUnit = [
|
||||
['Name', textField('tu_display_name', { type: 'text', disabled: mode.new ? false : true })],
|
||||
['Rank', dropdown('rank', rankOptions, 'Rank')],
|
||||
[
|
||||
'Sequence',
|
||||
<FieldWithTableSelection<SequenceDetailsType, TimeUnitDetailsType>
|
||||
key="sequence"
|
||||
sourceField="sequence"
|
||||
targetField="sequence"
|
||||
selectorTable={<SequenceTable />}
|
||||
/>,
|
||||
],
|
||||
['Sequence', <SequenceSelect key="sequence" />],
|
||||
['Comment', textField('tu_comment')],
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user