mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
fix: metadata batch edit silently fails due to split transactions and swallowed exceptions (#32041)
This commit is contained in:
@ -22,6 +22,7 @@ type MetadataItemWithEdit = {
|
||||
type: DataType
|
||||
value: string | number | null
|
||||
isMultipleValue?: boolean
|
||||
isUpdated?: boolean
|
||||
updateType?: UpdateType
|
||||
}
|
||||
|
||||
@ -615,6 +616,91 @@ describe('useBatchEditDocumentMetadata', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('toCleanMetadataItem sanitization', () => {
|
||||
it('should strip extra fields (isMultipleValue, updateType, isUpdated) from metadata items sent to backend', async () => {
|
||||
const docListSingleDoc: DocListItem[] = [
|
||||
{
|
||||
id: 'doc-1',
|
||||
doc_metadata: [
|
||||
{ id: '1', name: 'field_one', type: DataType.string, value: 'Old Value' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useBatchEditDocumentMetadata({
|
||||
...defaultProps,
|
||||
docList: docListSingleDoc as Parameters<typeof useBatchEditDocumentMetadata>[0]['docList'],
|
||||
}),
|
||||
)
|
||||
|
||||
const editedList: MetadataItemWithEdit[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'field_one',
|
||||
type: DataType.string,
|
||||
value: 'New Value',
|
||||
isMultipleValue: true,
|
||||
isUpdated: true,
|
||||
updateType: UpdateType.changeValue,
|
||||
},
|
||||
]
|
||||
|
||||
await act(async () => {
|
||||
await result.current.handleSave(editedList, [], false)
|
||||
})
|
||||
|
||||
const callArgs = mockMutateAsync.mock.calls[0][0]
|
||||
const sentItem = callArgs.metadata_list[0].metadata_list[0]
|
||||
|
||||
// Only id, name, type, value should be present
|
||||
expect(Object.keys(sentItem).sort()).toEqual(['id', 'name', 'type', 'value'].sort())
|
||||
expect(sentItem).not.toHaveProperty('isMultipleValue')
|
||||
expect(sentItem).not.toHaveProperty('updateType')
|
||||
expect(sentItem).not.toHaveProperty('isUpdated')
|
||||
})
|
||||
|
||||
it('should coerce undefined value to null in metadata items sent to backend', async () => {
|
||||
const docListSingleDoc: DocListItem[] = [
|
||||
{
|
||||
id: 'doc-1',
|
||||
doc_metadata: [
|
||||
{ id: '1', name: 'field_one', type: DataType.string, value: 'Value' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useBatchEditDocumentMetadata({
|
||||
...defaultProps,
|
||||
docList: docListSingleDoc as Parameters<typeof useBatchEditDocumentMetadata>[0]['docList'],
|
||||
}),
|
||||
)
|
||||
|
||||
// Pass an item with value explicitly set to undefined (via cast)
|
||||
const editedList: MetadataItemWithEdit[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'field_one',
|
||||
type: DataType.string,
|
||||
value: undefined as unknown as null,
|
||||
updateType: UpdateType.changeValue,
|
||||
},
|
||||
]
|
||||
|
||||
await act(async () => {
|
||||
await result.current.handleSave(editedList, [], false)
|
||||
})
|
||||
|
||||
const callArgs = mockMutateAsync.mock.calls[0][0]
|
||||
const sentItem = callArgs.metadata_list[0].metadata_list[0]
|
||||
|
||||
// value should be null, not undefined
|
||||
expect(sentItem.value).toBeNull()
|
||||
expect(sentItem.value).not.toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('should handle empty docList', () => {
|
||||
const { result } = renderHook(() =>
|
||||
|
||||
@ -71,6 +71,13 @@ const useBatchEditDocumentMetadata = ({
|
||||
return res
|
||||
}, [metaDataList])
|
||||
|
||||
const toCleanMetadataItem = (item: MetadataItemWithValue | MetadataItemWithEdit | MetadataItemInBatchEdit): MetadataItemWithValue => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
value: item.value ?? null,
|
||||
})
|
||||
|
||||
const formateToBackendList = (editedList: MetadataItemWithEdit[], addedList: MetadataItemInBatchEdit[], isApplyToAllSelectDocument: boolean) => {
|
||||
const updatedList = editedList.filter((editedItem) => {
|
||||
return editedItem.updateType === UpdateType.changeValue
|
||||
@ -92,24 +99,19 @@ const useBatchEditDocumentMetadata = ({
|
||||
.filter((item) => {
|
||||
return !removedList.find(removedItem => removedItem.id === item.id)
|
||||
})
|
||||
.map(item => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
value: item.value,
|
||||
}))
|
||||
.map(toCleanMetadataItem)
|
||||
if (isApplyToAllSelectDocument) {
|
||||
// add missing metadata item
|
||||
updatedList.forEach((editedItem) => {
|
||||
if (!newMetadataList.find(i => i.id === editedItem.id) && !editedItem.isMultipleValue)
|
||||
newMetadataList.push(editedItem)
|
||||
newMetadataList.push(toCleanMetadataItem(editedItem))
|
||||
})
|
||||
}
|
||||
|
||||
newMetadataList = newMetadataList.map((item) => {
|
||||
const editedItem = updatedList.find(i => i.id === item.id)
|
||||
if (editedItem)
|
||||
return editedItem
|
||||
return toCleanMetadataItem(editedItem)
|
||||
return item
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user