From c6ae9628af037746fa7455ed7f1942475ffb4364 Mon Sep 17 00:00:00 2001 From: twwu Date: Wed, 25 Jun 2025 16:15:59 +0800 Subject: [PATCH] feat: refactor input variable handling and configurations in pipeline processing components --- .../process-documents/hooks.ts | 47 +----------------- .../process-documents/index.tsx | 7 ++- .../detail/settings/document-settings.tsx | 6 ++- .../settings/pipeline-settings/index.tsx | 6 ++- .../process-documents/hooks.ts | 48 +------------------ .../process-documents/index.tsx | 7 ++- .../components/datasets/documents/index.tsx | 4 +- .../input-field/editor/form/hooks.ts | 15 ++++++ .../components/input-field/preview/form.tsx | 2 +- .../website-crawl/base/options/index.tsx | 2 +- .../test-run/document-processing/hooks.ts | 48 +------------------ .../test-run/document-processing/index.tsx | 7 ++- .../hooks.ts => hooks/use-input-fields.ts} | 20 ++++---- web/i18n/en-US/app-debug.ts | 1 + web/i18n/zh-Hans/app-debug.ts | 1 + web/service/knowledge/use-document.ts | 2 +- 16 files changed, 62 insertions(+), 161 deletions(-) rename web/app/components/rag-pipeline/{components/panel/test-run/data-source/website-crawl/base/options/hooks.ts => hooks/use-input-fields.ts} (78%) diff --git a/web/app/components/datasets/documents/create-from-pipeline/process-documents/hooks.ts b/web/app/components/datasets/documents/create-from-pipeline/process-documents/hooks.ts index 505cd5677c..4dcd901f3c 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/process-documents/hooks.ts +++ b/web/app/components/datasets/documents/create-from-pipeline/process-documents/hooks.ts @@ -1,58 +1,15 @@ -import { useMemo } from 'react' -import { BaseFieldType } from '@/app/components/base/form/form-scenarios/base/types' import { usePublishedPipelineProcessingParams } from '@/service/use-pipeline' -import { VAR_TYPE_MAP } from '@/models/pipeline' import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' -export const useConfigurations = (datasourceNodeId: string) => { +export const useInputVariables = (datasourceNodeId: string) => { const pipelineId = useDatasetDetailContextWithSelector(state => state.dataset?.pipeline_id) const { data: paramsConfig, isFetching: isFetchingParams } = usePublishedPipelineProcessingParams({ pipeline_id: pipelineId!, node_id: datasourceNodeId, }) - const initialData = useMemo(() => { - const variables = paramsConfig?.variables || [] - return variables.reduce((acc, item) => { - const type = VAR_TYPE_MAP[item.type] - if ([BaseFieldType.textInput, BaseFieldType.paragraph, BaseFieldType.select].includes(type)) - acc[item.variable] = item.default_value ?? '' - if (type === BaseFieldType.numberInput) - acc[item.variable] = item.default_value ?? 0 - if (type === BaseFieldType.checkbox) - acc[item.variable] = true - if ([BaseFieldType.file, BaseFieldType.fileList].includes(type)) - acc[item.variable] = [] - return acc - }, {} as Record) - }, [paramsConfig]) - - const configurations = useMemo(() => { - const variables = paramsConfig?.variables || [] - const configs = variables.map(item => ({ - type: VAR_TYPE_MAP[item.type], - variable: item.variable, - label: item.label, - required: item.required, - maxLength: item.max_length, - options: item.options?.map(option => ({ - label: option, - value: option, - })), - showConditions: [], - placeholder: item.placeholder, - tooltip: item.tooltips, - unit: item.unit, - allowedFileTypes: item.allowed_file_types, - allowedFileExtensions: item.allowed_file_extensions, - allowedFileUploadMethods: item.allowed_file_upload_methods, - })) - return configs - }, [paramsConfig]) - return { + paramsConfig, isFetchingParams, - initialData, - configurations, } } diff --git a/web/app/components/datasets/documents/create-from-pipeline/process-documents/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/process-documents/index.tsx index f47f884c00..0cb8f472d7 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/process-documents/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/process-documents/index.tsx @@ -1,8 +1,9 @@ import React from 'react' import { generateZodSchema } from '@/app/components/base/form/form-scenarios/base/utils' -import { useConfigurations } from './hooks' +import { useInputVariables } from './hooks' import Form from './form' import Actions from './actions' +import { useConfigurations, useInitialData } from '@/app/components/rag-pipeline/hooks/use-input-fields' type ProcessDocumentsProps = { dataSourceNodeId: string @@ -21,7 +22,9 @@ const ProcessDocuments = ({ onBack, ref, }: ProcessDocumentsProps) => { - const { isFetchingParams, initialData, configurations } = useConfigurations(dataSourceNodeId) + const { isFetchingParams, paramsConfig } = useInputVariables(dataSourceNodeId) + const initialData = useInitialData(paramsConfig?.variables || []) + const configurations = useConfigurations(paramsConfig?.variables || []) const schema = generateZodSchema(configurations) return ( diff --git a/web/app/components/datasets/documents/detail/settings/document-settings.tsx b/web/app/components/datasets/documents/detail/settings/document-settings.tsx index 0019da638f..199f77ca57 100644 --- a/web/app/components/datasets/documents/detail/settings/document-settings.tsx +++ b/web/app/components/datasets/documents/detail/settings/document-settings.tsx @@ -12,7 +12,7 @@ import AppUnavailable from '@/app/components/base/app-unavailable' import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks' import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import type { NotionPage } from '@/models/common' -import { useDocumentDetail, useInvalidDocumentDetailKey } from '@/service/knowledge/use-document' +import { useDocumentDetail, useInvalidDocumentDetail, useInvalidDocumentList } from '@/service/knowledge/use-document' type DocumentSettingsProps = { datasetId: string @@ -26,8 +26,10 @@ const DocumentSettings = ({ datasetId, documentId }: DocumentSettingsProps) => { const { indexingTechnique, dataset } = useContext(DatasetDetailContext) const { data: embeddingsDefaultModel } = useDefaultModel(ModelTypeEnum.textEmbedding) - const invalidDocumentDetail = useInvalidDocumentDetailKey() + const invalidDocumentList = useInvalidDocumentList(datasetId) + const invalidDocumentDetail = useInvalidDocumentDetail() const saveHandler = () => { + invalidDocumentList() invalidDocumentDetail() router.push(`/datasets/${datasetId}/documents/${documentId}`) } diff --git a/web/app/components/datasets/documents/detail/settings/pipeline-settings/index.tsx b/web/app/components/datasets/documents/detail/settings/pipeline-settings/index.tsx index 6b41544cd2..95e67f9466 100644 --- a/web/app/components/datasets/documents/detail/settings/pipeline-settings/index.tsx +++ b/web/app/components/datasets/documents/detail/settings/pipeline-settings/index.tsx @@ -13,7 +13,7 @@ import { DatasourceType } from '@/models/pipeline' import { noop } from 'lodash-es' import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' import { useRouter } from 'next/navigation' -import { useInvalidDocumentList } from '@/service/knowledge/use-document' +import { useInvalidDocumentDetail, useInvalidDocumentList } from '@/service/knowledge/use-document' type PipelineSettingsProps = { datasetId: string @@ -99,6 +99,7 @@ const PipelineSettings = ({ }, [lastRunData, pipelineId, runPublishedPipeline]) const invalidDocumentList = useInvalidDocumentList(datasetId) + const invalidDocumentDetail = useInvalidDocumentDetail() const handleProcess = useCallback(async (data: Record) => { if (!lastRunData) return @@ -115,10 +116,11 @@ const PipelineSettings = ({ }, { onSuccess: () => { invalidDocumentList() + invalidDocumentDetail() push(`/datasets/${datasetId}/documents/${documentId}`) }, }) - }, [datasetId, documentId, invalidDocumentList, lastRunData, pipelineId, push, runPublishedPipeline]) + }, [datasetId, documentId, invalidDocumentDetail, invalidDocumentList, lastRunData, pipelineId, push, runPublishedPipeline]) const onClickProcess = useCallback(() => { isPreview.current = false diff --git a/web/app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/hooks.ts b/web/app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/hooks.ts index 271d7abdde..bb4e872ff0 100644 --- a/web/app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/hooks.ts +++ b/web/app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/hooks.ts @@ -1,59 +1,15 @@ -import { useMemo } from 'react' import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' import { usePublishedPipelineProcessingParams } from '@/service/use-pipeline' -import { VAR_TYPE_MAP } from '@/models/pipeline' -import { BaseFieldType } from '@/app/components/base/form/form-scenarios/base/types' -export const useConfigurations = (lastRunInputData: Record, datasourceNodeId: string) => { +export const useInputVariables = (datasourceNodeId: string) => { const pipelineId = useDatasetDetailContextWithSelector(state => state.dataset?.pipeline_id) const { data: paramsConfig, isFetching: isFetchingParams } = usePublishedPipelineProcessingParams({ pipeline_id: pipelineId!, node_id: datasourceNodeId, }) - const initialData = useMemo(() => { - const variables = paramsConfig?.variables || [] - return variables.reduce((acc, item) => { - const type = VAR_TYPE_MAP[item.type] - const variableName = item.variable - if ([BaseFieldType.textInput, BaseFieldType.paragraph, BaseFieldType.select].includes(type)) - acc[item.variable] = lastRunInputData[variableName] ?? '' - if (type === BaseFieldType.numberInput) - acc[item.variable] = lastRunInputData[variableName] ?? 0 - if (type === BaseFieldType.checkbox) - acc[item.variable] = lastRunInputData[variableName] - if ([BaseFieldType.file, BaseFieldType.fileList].includes(type)) - acc[item.variable] = lastRunInputData[variableName] - return acc - }, {} as Record) - }, [lastRunInputData, paramsConfig?.variables]) - - const configurations = useMemo(() => { - const variables = paramsConfig?.variables || [] - const configs = variables.map(item => ({ - type: VAR_TYPE_MAP[item.type], - variable: item.variable, - label: item.label, - required: item.required, - maxLength: item.max_length, - options: item.options?.map(option => ({ - label: option, - value: option, - })), - showConditions: [], - placeholder: item.placeholder, - tooltip: item.tooltips, - unit: item.unit, - allowedFileTypes: item.allowed_file_types, - allowedFileExtensions: item.allowed_file_extensions, - allowedFileUploadMethods: item.allowed_file_upload_methods, - })) - return configs - }, [paramsConfig]) - return { + paramsConfig, isFetchingParams, - initialData, - configurations, } } diff --git a/web/app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/index.tsx b/web/app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/index.tsx index d68695ed09..da30f4be90 100644 --- a/web/app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/index.tsx +++ b/web/app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/index.tsx @@ -1,7 +1,8 @@ import { generateZodSchema } from '@/app/components/base/form/form-scenarios/base/utils' -import { useConfigurations } from './hooks' +import { useInputVariables } from './hooks' import Actions from './actions' import Form from '../../../../create-from-pipeline/process-documents/form' +import { useConfigurations, useInitialData } from '@/app/components/rag-pipeline/hooks/use-input-fields' type ProcessDocumentsProps = { datasourceNodeId: string @@ -20,7 +21,9 @@ const ProcessDocuments = ({ onSubmit, ref, }: ProcessDocumentsProps) => { - const { isFetchingParams, initialData, configurations } = useConfigurations(lastRunInputData, datasourceNodeId) + const { isFetchingParams, paramsConfig } = useInputVariables(datasourceNodeId) + const initialData = useInitialData(paramsConfig?.variables || [], lastRunInputData) + const configurations = useConfigurations(paramsConfig?.variables || []) const schema = generateZodSchema(configurations) return ( diff --git a/web/app/components/datasets/documents/index.tsx b/web/app/components/datasets/documents/index.tsx index 57f4cbc028..d21ae215d7 100644 --- a/web/app/components/datasets/documents/index.tsx +++ b/web/app/components/datasets/documents/index.tsx @@ -23,7 +23,7 @@ import { DataSourceType, ProcessMode } from '@/models/datasets' import IndexFailed from '@/app/components/datasets/common/document-status-with-action/index-failed' import { useProviderContext } from '@/context/provider-context' import cn from '@/utils/classnames' -import { useDocumentList, useInvalidDocumentDetailKey, useInvalidDocumentList } from '@/service/knowledge/use-document' +import { useDocumentList, useInvalidDocumentDetail, useInvalidDocumentList } from '@/service/knowledge/use-document' import { useInvalid } from '@/service/use-base' import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/use-segment' import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata' @@ -123,7 +123,7 @@ const Documents: FC = ({ datasetId }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [documentsRes]) - const invalidDocumentDetail = useInvalidDocumentDetailKey() + const invalidDocumentDetail = useInvalidDocumentDetail() const invalidChunkList = useInvalid(useSegmentListKey) const invalidChildChunkList = useInvalid(useChildSegmentListKey) diff --git a/web/app/components/rag-pipeline/components/input-field/editor/form/hooks.ts b/web/app/components/rag-pipeline/components/input-field/editor/form/hooks.ts index 1c9e714972..986a69c188 100644 --- a/web/app/components/rag-pipeline/components/input-field/editor/form/hooks.ts +++ b/web/app/components/rag-pipeline/components/input-field/editor/form/hooks.ts @@ -52,6 +52,12 @@ export const useHiddenFieldNames = (type: PipelineInputVarType) => { t('appDebug.variableConfig.tooltips'), ] break + case PipelineInputVarType.checkbox: + fieldNames = [ + t('appDebug.variableConfig.startedChecked'), + t('appDebug.variableConfig.tooltips'), + ] + break default: fieldNames = [ t('appDebug.variableConfig.tooltips'), @@ -258,6 +264,15 @@ export const useHiddenConfigurations = (props: { popupProps: { wrapperClassName: 'z-40', }, + }, { + type: InputFieldType.checkbox, + label: t('appDebug.variableConfig.startChecked'), + variable: 'default', + required: false, + showConditions: [{ + variable: 'type', + value: PipelineInputVarType.checkbox, + }], }, { type: InputFieldType.textInput, label: t('appDebug.variableConfig.placeholder'), diff --git a/web/app/components/rag-pipeline/components/input-field/preview/form.tsx b/web/app/components/rag-pipeline/components/input-field/preview/form.tsx index 0e67b084df..8420f6b7e3 100644 --- a/web/app/components/rag-pipeline/components/input-field/preview/form.tsx +++ b/web/app/components/rag-pipeline/components/input-field/preview/form.tsx @@ -1,7 +1,7 @@ import { useAppForm } from '@/app/components/base/form' import BaseField from '@/app/components/base/form/form-scenarios/base/field' import type { RAGPipelineVariables } from '@/models/pipeline' -import { useConfigurations, useInitialData } from '../../panel/test-run/data-source/website-crawl/base/options/hooks' +import { useConfigurations, useInitialData } from '@/app/components/rag-pipeline/hooks/use-input-fields' type FormProps = { variables: RAGPipelineVariables diff --git a/web/app/components/rag-pipeline/components/panel/test-run/data-source/website-crawl/base/options/index.tsx b/web/app/components/rag-pipeline/components/panel/test-run/data-source/website-crawl/base/options/index.tsx index 53ba3fc7f4..9b51590338 100644 --- a/web/app/components/rag-pipeline/components/panel/test-run/data-source/website-crawl/base/options/index.tsx +++ b/web/app/components/rag-pipeline/components/panel/test-run/data-source/website-crawl/base/options/index.tsx @@ -9,7 +9,7 @@ import { useEffect, useMemo } from 'react' import { useTranslation } from 'react-i18next' import Toast from '@/app/components/base/toast' import type { RAGPipelineVariables } from '@/models/pipeline' -import { useConfigurations, useInitialData } from './hooks' +import { useConfigurations, useInitialData } from '@/app/components/rag-pipeline/hooks/use-input-fields' import { generateZodSchema } from '@/app/components/base/form/form-scenarios/base/utils' const I18N_PREFIX = 'datasetCreation.stepOne.website' diff --git a/web/app/components/rag-pipeline/components/panel/test-run/document-processing/hooks.ts b/web/app/components/rag-pipeline/components/panel/test-run/document-processing/hooks.ts index 8c5fc73b95..d2029ddd24 100644 --- a/web/app/components/rag-pipeline/components/panel/test-run/document-processing/hooks.ts +++ b/web/app/components/rag-pipeline/components/panel/test-run/document-processing/hooks.ts @@ -1,59 +1,15 @@ -import { useMemo } from 'react' -import type { BaseConfiguration } from '@/app/components/base/form/form-scenarios/base/types' -import { BaseFieldType } from '@/app/components/base/form/form-scenarios/base/types' import { useStore } from '@/app/components/workflow/store' import { useDraftPipelineProcessingParams } from '@/service/use-pipeline' -import { VAR_TYPE_MAP } from '@/models/pipeline' -export const useConfigurations = (datasourceNodeId: string) => { +export const useInputVariables = (datasourceNodeId: string) => { const pipelineId = useStore(state => state.pipelineId) const { data: paramsConfig, isFetching: isFetchingParams } = useDraftPipelineProcessingParams({ pipeline_id: pipelineId!, node_id: datasourceNodeId, }) - const initialData = useMemo(() => { - const variables = paramsConfig?.variables || [] - return variables.reduce((acc, item) => { - const type = VAR_TYPE_MAP[item.type] - if ([BaseFieldType.textInput, BaseFieldType.paragraph, BaseFieldType.select].includes(type)) - acc[item.variable] = item.default_value ?? '' - if (type === BaseFieldType.numberInput) - acc[item.variable] = item.default_value ?? 0 - if (type === BaseFieldType.checkbox) - acc[item.variable] = true - if ([BaseFieldType.file, BaseFieldType.fileList].includes(type)) - acc[item.variable] = [] - return acc - }, {} as Record) - }, [paramsConfig]) - - const configurations = useMemo(() => { - const variables = paramsConfig?.variables || [] - const configs: BaseConfiguration[] = variables.map(item => ({ - type: VAR_TYPE_MAP[item.type], - variable: item.variable, - label: item.label, - required: item.required, - maxLength: item.max_length, - options: item.options?.map(option => ({ - label: option, - value: option, - })), - showConditions: [], - placeholder: item.placeholder, - tooltip: item.tooltips, - unit: item.unit, - allowedFileTypes: item.allowed_file_types, - allowedFileExtensions: item.allowed_file_extensions, - allowedFileUploadMethods: item.allowed_file_upload_methods, - })) - return configs - }, [paramsConfig]) - return { isFetchingParams, - initialData, - configurations, + paramsConfig, } } diff --git a/web/app/components/rag-pipeline/components/panel/test-run/document-processing/index.tsx b/web/app/components/rag-pipeline/components/panel/test-run/document-processing/index.tsx index 6870a65c2a..f102f35fc4 100644 --- a/web/app/components/rag-pipeline/components/panel/test-run/document-processing/index.tsx +++ b/web/app/components/rag-pipeline/components/panel/test-run/document-processing/index.tsx @@ -1,9 +1,10 @@ import React, { useCallback } from 'react' import { generateZodSchema } from '@/app/components/base/form/form-scenarios/base/utils' -import { useConfigurations } from './hooks' +import { useInputVariables } from './hooks' import Options from './options' import Actions from './actions' import type { CustomActionsProps } from '@/app/components/base/form/components/form/actions' +import { useConfigurations, useInitialData } from '@/app/components/rag-pipeline/hooks/use-input-fields' type DocumentProcessingProps = { dataSourceNodeId: string @@ -16,7 +17,9 @@ const DocumentProcessing = ({ onProcess, onBack, }: DocumentProcessingProps) => { - const { isFetchingParams, initialData, configurations } = useConfigurations(dataSourceNodeId) + const { isFetchingParams, paramsConfig } = useInputVariables(dataSourceNodeId) + const initialData = useInitialData(paramsConfig?.variables || []) + const configurations = useConfigurations(paramsConfig?.variables || []) const schema = generateZodSchema(configurations) const renderCustomActions = useCallback((props: CustomActionsProps) => ( diff --git a/web/app/components/rag-pipeline/components/panel/test-run/data-source/website-crawl/base/options/hooks.ts b/web/app/components/rag-pipeline/hooks/use-input-fields.ts similarity index 78% rename from web/app/components/rag-pipeline/components/panel/test-run/data-source/website-crawl/base/options/hooks.ts rename to web/app/components/rag-pipeline/hooks/use-input-fields.ts index e4218ba07a..275d49a4ed 100644 --- a/web/app/components/rag-pipeline/components/panel/test-run/data-source/website-crawl/base/options/hooks.ts +++ b/web/app/components/rag-pipeline/hooks/use-input-fields.ts @@ -1,23 +1,25 @@ -import type { BaseConfiguration } from '@/app/components/base/form/form-scenarios/base/types' -import { BaseFieldType } from '@/app/components/base/form/form-scenarios/base/types' -import { type RAGPipelineVariables, VAR_TYPE_MAP } from '@/models/pipeline' import { useMemo } from 'react' +import type { BaseConfiguration } from '@/app/components/base/form/form-scenarios/base/types' +import { type RAGPipelineVariables, VAR_TYPE_MAP } from '@/models/pipeline' +import { BaseFieldType } from '@/app/components/base/form/form-scenarios/base/types' -export const useInitialData = (variables: RAGPipelineVariables) => { +export const useInitialData = (variables: RAGPipelineVariables, lastRunInputData?: Record) => { const initialData = useMemo(() => { return variables.reduce((acc, item) => { const type = VAR_TYPE_MAP[item.type] + const variableName = item.variable + const defaultValue = lastRunInputData?.[variableName] || item.default_value if ([BaseFieldType.textInput, BaseFieldType.paragraph, BaseFieldType.select].includes(type)) - acc[item.variable] = item.default_value ?? '' + acc[variableName] = defaultValue ?? '' if (type === BaseFieldType.numberInput) - acc[item.variable] = item.default_value ?? 0 + acc[variableName] = defaultValue ?? 0 if (type === BaseFieldType.checkbox) - acc[item.variable] = true + acc[variableName] = defaultValue ?? false if ([BaseFieldType.file, BaseFieldType.fileList].includes(type)) - acc[item.variable] = [] + acc[variableName] = defaultValue ?? [] return acc }, {} as Record) - }, [variables]) + }, [lastRunInputData, variables]) return initialData } diff --git a/web/i18n/en-US/app-debug.ts b/web/i18n/en-US/app-debug.ts index 43442ca79d..d83446ee46 100644 --- a/web/i18n/en-US/app-debug.ts +++ b/web/i18n/en-US/app-debug.ts @@ -414,6 +414,7 @@ const translation = { atLeastOneOption: 'At least one option is required', optionRepeat: 'Has repeat options', }, + 'startChecked': 'Start checked', }, vision: { name: 'Vision', diff --git a/web/i18n/zh-Hans/app-debug.ts b/web/i18n/zh-Hans/app-debug.ts index b57120a643..cab06c57bb 100644 --- a/web/i18n/zh-Hans/app-debug.ts +++ b/web/i18n/zh-Hans/app-debug.ts @@ -408,6 +408,7 @@ const translation = { atLeastOneOption: '至少需要一个选项', optionRepeat: '选项不能重复', }, + 'startChecked': '默认勾选', }, vision: { name: '视觉', diff --git a/web/service/knowledge/use-document.ts b/web/service/knowledge/use-document.ts index 6dabe7d872..aeee91d986 100644 --- a/web/service/knowledge/use-document.ts +++ b/web/service/knowledge/use-document.ts @@ -127,6 +127,6 @@ export const useDocumentMetadata = (payload: { }) } -export const useInvalidDocumentDetailKey = () => { +export const useInvalidDocumentDetail = () => { return useInvalid(useDocumentDetailKey) }