refactor: Refactor context generate modal storage key management

This commit is contained in:
zhsama
2026-01-30 22:55:13 +08:00
parent b67d0d8c45
commit d0d553ba38
10 changed files with 400 additions and 45 deletions

View File

@ -1,5 +1,6 @@
import type { ReactNode } from 'react'
import type { ContextGenerateChatMessage } from '../hooks/use-context-generate'
import type { VersionOption } from '../types'
import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { TriggerProps } from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger'
import type { Model } from '@/types/app'
@ -12,11 +13,6 @@ import { CodeAssistant } from '@/app/components/base/icons/src/vender/line/gener
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
import { cn } from '@/utils/classnames'
type VersionOption = {
index: number
label: string
}
type ChatViewProps = {
promptMessages: ContextGenerateChatMessage[]
versionOptions: VersionOption[]
@ -81,9 +77,10 @@ const ChatView = ({
const versionMeta = assistantVersionMap[index]
const isSelected = versionMeta?.index === currentVersionIndex
const assistantContent = message.content || defaultAssistantMessage
const messageKey = message.id || `${message.role}-${index}`
return (
<div
key={`${message.role}-${index}`}
key={messageKey}
className={cn('flex w-full', message.role === 'user' ? 'justify-end' : 'justify-start')}
>
{message.role === 'user'
@ -164,7 +161,7 @@ const ChatView = ({
<Button
variant="primary"
size="small"
className="!h-8 !w-8 shrink-0 !rounded-lg !px-0"
className="ml-auto !h-8 !w-8 shrink-0 !rounded-lg !px-0"
disabled={!inputValue.trim() || isGenerating}
onClick={onGenerate}
>

View File

@ -1,4 +1,5 @@
import type { ContextGenerateChatMessage } from '../hooks/use-context-generate'
import type { VersionOption } from '../types'
import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { TriggerProps } from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger'
import type { Model } from '@/types/app'
@ -14,11 +15,6 @@ import { renderI18nObject } from '@/i18n-config'
import { cn } from '@/utils/classnames'
import ChatView from './chat-view'
type VersionOption = {
index: number
label: string
}
type LeftPanelProps = {
isInitView: boolean
isGenerating: boolean

View File

@ -1,4 +1,5 @@
import type { PointerEvent, RefObject } from 'react'
import type { VersionOption } from '../types'
import type { ContextGenerateResponse } from '@/service/debug'
import { RiArrowDownSLine, RiCheckLine, RiCloseLine, RiPlayLargeLine } from '@remixicon/react'
import { useCallback, useMemo, useState } from 'react'
@ -13,11 +14,6 @@ import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import { cn } from '@/utils/classnames'
type VersionOption = {
index: number
label: string
}
type DisplayOutputData = {
variables: ContextGenerateResponse['variables']
outputs: ContextGenerateResponse['outputs']
@ -83,9 +79,12 @@ const RightPanel = ({
setVersionMenuOpen(value => !value)
}, [versionOptions.length])
const codeLanguageLabel = displayCodeLanguage === CodeLanguage.javascript
? t('nodes.tool.contextGenerate.codeLanguage.javascript', { ns: 'workflow' })
: t('nodes.tool.contextGenerate.codeLanguage.python3', { ns: 'workflow' })
const codeLanguageLabel = useMemo(() => {
return t(`nodes.tool.contextGenerate.codeLanguage.${displayCodeLanguage}`, {
ns: 'workflow',
defaultValue: displayCodeLanguage,
})
}, [displayCodeLanguage, t])
const emptyPanelClassName = cn(
'flex h-full flex-col',

View File

@ -1,21 +1,26 @@
import type { ContextGenerateResponse } from '@/service/debug'
import { useSessionStorageState } from 'ahooks'
import { useCallback } from 'react'
import { CONTEXT_GEN_STORAGE_SUFFIX, getContextGenStorageKey } from '../utils/storage'
type Params = {
storageKey: string
}
const keyPrefix = 'context-gen-'
const useContextGenData = ({ storageKey }: Params) => {
const [versions, setVersions] = useSessionStorageState<ContextGenerateResponse[]>(`${keyPrefix}${storageKey}-versions`, {
defaultValue: [],
})
const [versions, setVersions] = useSessionStorageState<ContextGenerateResponse[]>(
getContextGenStorageKey(storageKey, CONTEXT_GEN_STORAGE_SUFFIX.versions),
{
defaultValue: [],
},
)
const [currentVersionIndex, setCurrentVersionIndex] = useSessionStorageState<number>(`${keyPrefix}${storageKey}-version-index`, {
defaultValue: 0,
})
const [currentVersionIndex, setCurrentVersionIndex] = useSessionStorageState<number>(
getContextGenStorageKey(storageKey, CONTEXT_GEN_STORAGE_SUFFIX.versionIndex),
{
defaultValue: 0,
},
)
const current = versions?.[currentVersionIndex || 0]

View File

@ -1,3 +1,4 @@
import type { VersionOption } from '../types'
import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { ToolParameter } from '@/app/components/tools/types'
import type { CodeNodeType } from '@/app/components/workflow/nodes/code/types'
@ -25,9 +26,11 @@ import { useGetLanguage } from '@/context/i18n'
import { languages } from '@/i18n-config/language'
import { fetchContextGenerateSuggestedQuestions, generateContext } from '@/service/debug'
import { AppModeEnum } from '@/types/app'
import { CONTEXT_GEN_STORAGE_SUFFIX, getContextGenStorageKey } from '../utils/storage'
import useContextGenData from './use-context-gen-data'
export type ContextGenerateChatMessage = ContextGenerateMessage & {
id?: string
durationMs?: number
}
@ -39,6 +42,10 @@ export const normalizeCodeLanguage = (value?: string) => {
return CodeLanguage.python3
}
const createChatMessageId = () => {
return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
}
const buildValueSelector = (nodeId: string, variable: Var): ValueSelector => {
if (!nodeId)
return variable.variable.split('.')
@ -128,11 +135,6 @@ type UseContextGenerateOptions = {
availableNodes?: Node[]
}
type VersionOption = {
index: number
label: string
}
type UseContextGenerateResult = {
versions: ContextGenerateResponse[]
current: ContextGenerateResponse | undefined
@ -180,7 +182,7 @@ const useContextGenerate = ({
})
const [promptMessages, setPromptMessages] = useSessionStorageState<ContextGenerateChatMessage[]>(
`${storageKey}-messages`,
getContextGenStorageKey(storageKey, CONTEXT_GEN_STORAGE_SUFFIX.messages),
{ defaultValue: [] },
)
@ -449,7 +451,7 @@ const useContextGenerate = ({
if (!toolNodeId || !paramKey)
return
const userMessage: ContextGenerateChatMessage = { role: 'user', content: trimmed }
const userMessage: ContextGenerateChatMessage = { role: 'user', content: trimmed, id: createChatMessageId() }
const nextMessages: ContextGenerateChatMessage[] = [...(promptMessages ?? []), userMessage]
setPromptMessages(nextMessages)
setInputValue('')
@ -485,6 +487,7 @@ const useContextGenerate = ({
role: 'assistant',
content: assistantMessage,
durationMs,
id: createChatMessageId(),
}
setPromptMessages([...nextMessages, assistantEntry])
addVersion(response)

View File

@ -14,6 +14,7 @@ import LeftPanel from './components/left-panel'
import RightPanel from './components/right-panel'
import useContextGenerate, { normalizeCodeLanguage } from './hooks/use-context-generate'
import useResizablePanels from './hooks/use-resizable-panels'
import { buildContextGenStorageKey } from './utils/storage'
type Props = {
isShow: boolean
@ -69,8 +70,7 @@ const ContextGenerateModal = forwardRef<ContextGenerateModalHandle, Props>(({
const flowId = configsMap?.flowId || ''
const storageKey = useMemo(() => {
const segments = [flowId || 'unknown', toolNodeId, paramKey].filter(Boolean)
return segments.join('-')
return buildContextGenStorageKey(flowId, toolNodeId, paramKey)
}, [flowId, paramKey, toolNodeId])
const codeNode = useMemo(() => {

View File

@ -0,0 +1,4 @@
export type VersionOption = {
index: number
label: string
}

View File

@ -1,9 +1,18 @@
// Storage key prefix used by useContextGenData
const CONTEXT_GEN_PREFIX = 'context-gen-'
export const CONTEXT_GEN_STORAGE_SUFFIX = {
versions: 'versions',
versionIndex: 'version-index',
messages: 'messages',
suggestedQuestions: 'suggested-questions',
suggestedQuestionsFetched: 'suggested-questions-fetched',
} as const
export type ContextGenStorageSuffix = typeof CONTEXT_GEN_STORAGE_SUFFIX[keyof typeof CONTEXT_GEN_STORAGE_SUFFIX]
/**
* Build storage key from flowId, toolNodeId, and paramKey.
* Mirrors the logic in context-generate-modal/index.tsx.
*/
export const buildContextGenStorageKey = (
flowId: string | undefined,
@ -14,13 +23,21 @@ export const buildContextGenStorageKey = (
return segments.join('-')
}
const buildContextGenStorageKeyWithPrefix = (storageKey: string, suffix: ContextGenStorageSuffix): string => {
return `${CONTEXT_GEN_PREFIX}${storageKey}-${suffix}`
}
export const getContextGenStorageKey = (storageKey: string, suffix: ContextGenStorageSuffix): string => {
return buildContextGenStorageKeyWithPrefix(storageKey, suffix)
}
export const getContextGenStorageKeys = (storageKey: string): string[] => {
return [
`${CONTEXT_GEN_PREFIX}${storageKey}-versions`,
`${CONTEXT_GEN_PREFIX}${storageKey}-version-index`,
`${storageKey}-messages`,
`${storageKey}-suggested-questions`,
`${storageKey}-suggested-questions-fetched`,
getContextGenStorageKey(storageKey, CONTEXT_GEN_STORAGE_SUFFIX.versions),
getContextGenStorageKey(storageKey, CONTEXT_GEN_STORAGE_SUFFIX.versionIndex),
getContextGenStorageKey(storageKey, CONTEXT_GEN_STORAGE_SUFFIX.messages),
getContextGenStorageKey(storageKey, CONTEXT_GEN_STORAGE_SUFFIX.suggestedQuestions),
getContextGenStorageKey(storageKey, CONTEXT_GEN_STORAGE_SUFFIX.suggestedQuestionsFetched),
]
}