mirror of
https://github.com/langgenius/dify.git
synced 2026-08-01 01:49:30 +08:00
90 lines
3.3 KiB
TypeScript
90 lines
3.3 KiB
TypeScript
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
import { taskVersionIsAfter } from './document-model'
|
|
|
|
export type AuxiliaryTaskReadGuard = ReturnType<typeof createAuxiliaryTaskReadGuard>
|
|
|
|
type RefetchDocuments = (options: { cancelRefetch: true }) => Promise<{ error: unknown }>
|
|
|
|
export function createAuxiliaryTaskReadGuard() {
|
|
const blockedVersions = new Map<string, string>()
|
|
|
|
return {
|
|
block(taskId: string, taskVersion: string) {
|
|
const blockedVersion = blockedVersions.get(taskId)
|
|
if (blockedVersion && taskVersionIsAfter(blockedVersion, taskVersion)) return
|
|
blockedVersions.set(taskId, taskVersion)
|
|
},
|
|
clear() {
|
|
blockedVersions.clear()
|
|
},
|
|
clearTask(taskId: string) {
|
|
blockedVersions.delete(taskId)
|
|
},
|
|
clearThrough(taskId: string, authoritativeVersion: string) {
|
|
const blockedVersion = blockedVersions.get(taskId)
|
|
if (!blockedVersion || taskVersionIsAfter(blockedVersion, authoritativeVersion)) return false
|
|
blockedVersions.delete(taskId)
|
|
return true
|
|
},
|
|
isBlocked(taskId: string, taskVersion: string) {
|
|
const blockedVersion = blockedVersions.get(taskId)
|
|
return Boolean(blockedVersion && !taskVersionIsAfter(taskVersion, blockedVersion))
|
|
},
|
|
retain(taskIds: Set<string>) {
|
|
for (const taskId of blockedVersions.keys()) {
|
|
if (!taskIds.has(taskId)) blockedVersions.delete(taskId)
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
export function useAuxiliaryTaskReadGuard({
|
|
documentPermissionDenied,
|
|
refetchDocuments,
|
|
}: {
|
|
documentPermissionDenied: boolean
|
|
refetchDocuments: RefetchDocuments
|
|
}) {
|
|
const guardRef = useRef<AuxiliaryTaskReadGuard | null>(null)
|
|
if (!guardRef.current) guardRef.current = createAuxiliaryTaskReadGuard()
|
|
const guard = guardRef.current
|
|
const previousDocumentPermissionDeniedRef = useRef(documentPermissionDenied)
|
|
const denialGenerationRef = useRef(0)
|
|
const [permissionDenied, setPermissionDenied] = useState(false)
|
|
const [guardRevision, setGuardRevision] = useState(0)
|
|
|
|
useEffect(() => {
|
|
const wasDenied = previousDocumentPermissionDeniedRef.current
|
|
previousDocumentPermissionDeniedRef.current = documentPermissionDenied
|
|
if (!wasDenied || documentPermissionDenied) return
|
|
guard.clear()
|
|
// oxlint-disable-next-line eslint-react/set-state-in-effect -- The authoritative document permission transition retires the local denial.
|
|
setPermissionDenied(false)
|
|
// oxlint-disable-next-line eslint-react/set-state-in-effect -- Guard mutations need one render so blocked readers are reconsidered.
|
|
setGuardRevision((current) => current + 1)
|
|
}, [documentPermissionDenied, guard])
|
|
|
|
const retry = useCallback(() => {
|
|
const denialGeneration = denialGenerationRef.current + 1
|
|
denialGenerationRef.current = denialGeneration
|
|
setPermissionDenied(true)
|
|
void refetchDocuments({ cancelRefetch: true }).then(
|
|
(result) => {
|
|
if (denialGenerationRef.current === denialGeneration && !result.error)
|
|
setPermissionDenied(false)
|
|
},
|
|
() => undefined,
|
|
)
|
|
}, [refetchDocuments])
|
|
|
|
const deny = useCallback(
|
|
(taskId: string, taskVersion: string) => {
|
|
guard.block(taskId, taskVersion)
|
|
retry()
|
|
},
|
|
[guard, retry],
|
|
)
|
|
|
|
return { deny, guard, guardRevision, permissionDenied, retry }
|
|
}
|