Skip to content

Commit 96a462d

Browse files
xIrusuxclaude
andcommitted
[Batch Delete] Fix check-types error and align the folder delete-info preflight
The batch pre-check passed a possibly-undefined RTK error into ApiError (TS2345 in check-types); guard it like use-open-saved-search does. The single-folder delete flow had the same preflight bug class the batch flow just fixed, but worse: elementGetDeleteInfo failures were entirely unhandled, silently falling back to the harmless recoverable-delete wording even when deletion would be permanent, and the query subscription was never released. Failures now raise the API error and abort instead of opening a possibly under-warning dialog; the two almost-identical modal configs are merged. Refs #3961 Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 9ce0a46 commit 96a462d

2 files changed

Lines changed: 36 additions & 33 deletions

File tree

assets/js/src/core/modules/element/actions/delete/use-batch-delete-confirm.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
import React from 'react'
12+
import { isUndefined } from 'lodash'
1213
import { useTranslation } from 'react-i18next'
1314
import { Accordion } from '@Pimcore/components/accordion/accordion'
1415
import { useFormModal } from '@Pimcore/components/modal/form-modal/hooks/use-form-modal'
@@ -53,7 +54,9 @@ export const useBatchDeleteConfirm = (): UseBatchDeleteConfirmReturn => {
5354
const response = await request
5455

5556
if ('error' in response) {
56-
trackError(new ApiError(response.error))
57+
if (!isUndefined(response.error)) {
58+
trackError(new ApiError(response.error))
59+
}
5760
return null
5861
}
5962

assets/js/src/core/modules/element/actions/delete/use-delete.tsx

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import type { TreeNodeProps } from '@Pimcore/components/element-tree/node/tree-n
1515
import type { GridContextMenuProps } from '@Pimcore/components/grid/grid'
1616
import { Icon } from '@Pimcore/components/icon/icon'
1717
import { useFormModal } from '@Pimcore/components/modal/form-modal/hooks/use-form-modal'
18-
import trackError, { GeneralError } from '@Pimcore/modules/app/error-handler'
18+
import { isUndefined } from 'lodash'
19+
import trackError, { ApiError, GeneralError } from '@Pimcore/modules/app/error-handler'
1920
import { useRefreshGrid } from '@Pimcore/modules/element/actions/refresh-grid/use-refresh-grid'
2021
import { type Element, getElementKey } from '@Pimcore/modules/element/element-helper'
2122
import { api as elementApi } from '@Pimcore/modules/element/element-api-slice.gen'
@@ -91,39 +92,38 @@ export const useDelete = (elementType: ElementType, cacheKey?: string): UseDelet
9192
}
9293
}
9394

95+
const confirmFolderDelete = async (id: number, label: string, parentId?: number, onFinish?: () => void): Promise<void> => {
96+
const request = dispatch(elementApi.endpoints.elementGetDeleteInfo.initiate({ elementType, id }))
97+
98+
try {
99+
const { data, error } = await request
100+
101+
if (!isUndefined(error)) {
102+
trackError(new ApiError(error))
103+
return
104+
}
105+
106+
const canUseRecycleBin = data?.canUseRecycleBin ?? true
107+
108+
modal.confirm({
109+
title: t('element.delete.folder.title'),
110+
content: <>
111+
<p><span className={ styles.warningText }>{t(canUseRecycleBin ? 'element.delete.folder.small.note' : 'element.delete.folder.large.note')}</span></p>
112+
<p>{t('element.delete.folder.question')}</p>
113+
<b>/{label}</b>
114+
</>,
115+
cancelText: t('cancel'),
116+
okText: t(canUseRecycleBin ? 'element.delete.folder.ok' : 'element.delete.folder.ok.permanent'),
117+
onOk: async () => { await runDeleteJob(id, parentId, onFinish) }
118+
})
119+
} finally {
120+
request.unsubscribe()
121+
}
122+
}
123+
94124
const deleteElement = (id: number, label: string, parentId?: number, onFinish?: () => void, isFolder?: boolean): void => {
95125
if (isFolder === true) {
96-
void dispatch(elementApi.endpoints.elementGetDeleteInfo.initiate({ elementType, id }))
97-
.then(({ data }) => {
98-
const canUseRecycleBin = data?.canUseRecycleBin ?? true
99-
100-
if (canUseRecycleBin) {
101-
modal.confirm({
102-
title: t('element.delete.folder.title'),
103-
content: <>
104-
<p><span className={ styles.warningText }>{t('element.delete.folder.small.note')}</span></p>
105-
<p>{t('element.delete.folder.question')}</p>
106-
<b>/{label}</b>
107-
</>,
108-
cancelText: t('cancel'),
109-
okText: t('element.delete.folder.ok'),
110-
onOk: async () => { await runDeleteJob(id, parentId, onFinish) }
111-
})
112-
} else {
113-
modal.confirm({
114-
title: t('element.delete.folder.title'),
115-
content: <>
116-
<p><span className={ styles.warningText }>{t('element.delete.folder.large.note')}</span></p>
117-
<p>{t('element.delete.folder.question')}</p>
118-
<b>/{label}</b>
119-
</>,
120-
cancelText: t('cancel'),
121-
okText: t('element.delete.folder.ok.permanent'),
122-
123-
onOk: async () => { await runDeleteJob(id, parentId, onFinish) }
124-
})
125-
}
126-
})
126+
void confirmFolderDelete(id, label, parentId, onFinish)
127127
} else {
128128
modal.confirm({
129129
title: t('element.delete.confirmation.title'),

0 commit comments

Comments
 (0)