= {}
if (fileContent.metadata) {
if (typeof fileContent.metadata === 'string') {
try {
nextMetadata = JSON.parse(fileContent.metadata)
}
catch {
nextMetadata = {}
}
}
else {
nextMetadata = fileContent.metadata
}
}
const { setFileMetadata, clearDraftMetadata } = storeApi.getState()
setFileMetadata(fileTabId, nextMetadata)
clearDraftMetadata(fileTabId)
}, [fileTabId, isMetadataDirty, fileContent, storeApi])
const handleEditorChange = useCallback((value: string | undefined) => {
if (!fileTabId || !isEditable)
return
const newValue = value ?? ''
if (newValue === originalContent)
storeApi.getState().clearDraftContent(fileTabId)
else
storeApi.getState().setDraftContent(fileTabId, newValue)
storeApi.getState().pinTab(fileTabId)
}, [fileTabId, isEditable, originalContent, storeApi])
const { saveFile, registerFallback, unregisterFallback } = useSkillSaveManager()
const fallbackRef = useRef({ content: originalContent, metadata: currentMetadata })
useEffect(() => {
if (!fileTabId || fileContent?.content === undefined)
return
const fallback = { content: originalContent, metadata: currentMetadata }
fallbackRef.current = fallback
registerFallback(fileTabId, fallback)
return () => {
unregisterFallback(fileTabId)
}
}, [fileTabId, fileContent?.content, originalContent, currentMetadata, registerFallback, unregisterFallback])
useEffect(() => {
if (!fileTabId || !isEditable)
return
return () => {
const { content: fallbackContent, metadata: fallbackMetadata } = fallbackRef.current
void saveFile(fileTabId, {
fallbackContent,
fallbackMetadata,
})
}
}, [fileTabId, isEditable, saveFile])
const handleEditorDidMount: OnMount = useCallback((editor, monaco) => {
editorRef.current = editor
monaco.editor.setTheme(appTheme === Theme.light ? 'light' : 'vs-dark')
setIsMounted(true)
}, [appTheme])
const language = currentFileNode ? getFileLanguage(currentFileNode.name) : 'plaintext'
const theme = appTheme === Theme.light ? 'light' : 'vs-dark'
if (isStartTab)
return
if (!fileTabId) {
return (
{t('skillSidebar.empty')}
)
}
if (isLoading) {
return (
)
}
if (error) {
return (
{t('skillSidebar.loadError')}
)
}
// For non-editable files (media, sqlite, unsupported), use download URL
const downloadUrl = downloadUrlData?.download_url || ''
const fileName = currentFileNode?.name || ''
const fileSize = currentFileNode?.size
const isUnsupportedFile = !isMarkdown && !isCodeOrText && !isImage && !isVideo && !isSQLite
return (
{isMarkdown
? (
)
: null}
{isCodeOrText
? (
)
: null}
{isImage || isVideo
? (
)
: null}
{isSQLite
? (
)
: null}
{isUnsupportedFile
? (
)
: null}
)
}
export default React.memo(FileContentPanel)