|
|
import type { TextAnalysisAPI } from '../api/GLTR_API'; |
|
|
import type { AnalyzeResponse } from '../api/GLTR_API'; |
|
|
import { showDialog, createCombinedContent, showAlertDialog, showConfirmDialog } from '../ui/dialog'; |
|
|
import { createRawSnapshot } from '../utils/tokenUtils'; |
|
|
import { ServerStorage } from '../storage/demoStorage'; |
|
|
import { DemoStorageController } from './demoStorageController'; |
|
|
import type { IDemoStorage } from '../storage/demoStorage'; |
|
|
import { |
|
|
normalizeFolderPath, |
|
|
composeDemoFullPath, |
|
|
getDefaultDemoName, |
|
|
buildFolderOptions |
|
|
} from '../utils/demoPathUtils'; |
|
|
import { tr, trf } from '../lang/i18n-lite'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const extractSavedFileName = (saveResult: any, defaultName: string): string => { |
|
|
if (saveResult && typeof saveResult.file === 'string' && saveResult.file.trim()) { |
|
|
return saveResult.file.trim(); |
|
|
} |
|
|
const trimmed = defaultName.trim(); |
|
|
return trimmed.toLowerCase().endsWith('.json') ? trimmed : `${trimmed}.json`; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const showDemoNameInput = ( |
|
|
api: TextAnalysisAPI, |
|
|
defaultName: string |
|
|
): Promise<{ name: string, path: string } | null> => { |
|
|
const LAST_SAVE_PATH_KEY = 'lastSaveDemoPath'; |
|
|
|
|
|
return new Promise((resolve) => { |
|
|
|
|
|
api.list_all_folders() |
|
|
.then((result: { folders: string[] }) => { |
|
|
const folders = result.folders || []; |
|
|
|
|
|
|
|
|
const lastSavePath = localStorage.getItem(LAST_SAVE_PATH_KEY); |
|
|
|
|
|
|
|
|
const { options: selectOptions, defaultPath } = buildFolderOptions(folders, lastSavePath); |
|
|
|
|
|
|
|
|
showDialog({ |
|
|
title: tr('Please enter demo name:'), |
|
|
content: createCombinedContent( |
|
|
tr('Demo name:'), |
|
|
defaultName, |
|
|
tr('Save directory:'), |
|
|
selectOptions, |
|
|
defaultPath |
|
|
), |
|
|
onConfirm: (value: { input: string; select: string }) => { |
|
|
if (value && value.input) { |
|
|
|
|
|
const selectedPath = value.select || '/'; |
|
|
localStorage.setItem(LAST_SAVE_PATH_KEY, selectedPath); |
|
|
resolve({ name: value.input, path: selectedPath }); |
|
|
} else { |
|
|
resolve(null); |
|
|
} |
|
|
}, |
|
|
onCancel: () => { |
|
|
resolve(null); |
|
|
}, |
|
|
cancelText: tr('Cancel') |
|
|
}); |
|
|
}) |
|
|
.catch((error) => { |
|
|
console.error('加载文件夹列表失败:', error); |
|
|
const errorMessage = error instanceof Error ? error.message : String(error); |
|
|
showAlertDialog(tr('Error'), trf('Failed to load folder list: {message}', { message: errorMessage })); |
|
|
resolve(null); |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
|
|
|
export type ServerDemoSaveOptions = { |
|
|
api: TextAnalysisAPI; |
|
|
currentData: AnalyzeResponse | null; |
|
|
rawApiResponse: AnalyzeResponse | null; |
|
|
textFieldValue: string; |
|
|
enableDemo: boolean; |
|
|
demoManager?: { |
|
|
loadDemoByPath: (path: string) => Promise<boolean>; |
|
|
highlightDemo: (path: string | null) => void; |
|
|
refresh: () => Promise<void>; |
|
|
} | null; |
|
|
|
|
|
|
|
|
|
|
|
presetSaveInfo?: { |
|
|
name: string; |
|
|
path?: string | null; |
|
|
} | null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
showSuccessToast?: boolean; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
serverStorage?: IDemoStorage; |
|
|
|
|
|
|
|
|
|
|
|
currentFileName?: string | null; |
|
|
onSaveStart: () => void; |
|
|
onSaveSuccess: (name: string) => void; |
|
|
onSaveError: (error: Error) => void; |
|
|
setGlobalLoading: (loading: boolean) => void; |
|
|
showToast: (message: string, type: 'success' | 'error') => void; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const handleServerDemoSave = async (options: ServerDemoSaveOptions): Promise<void> => { |
|
|
const { |
|
|
api, |
|
|
currentData, |
|
|
rawApiResponse, |
|
|
textFieldValue, |
|
|
enableDemo, |
|
|
demoManager, |
|
|
presetSaveInfo = null, |
|
|
showSuccessToast = true, |
|
|
serverStorage: providedStorage, |
|
|
currentFileName = null, |
|
|
onSaveStart, |
|
|
onSaveSuccess, |
|
|
onSaveError, |
|
|
setGlobalLoading, |
|
|
showToast |
|
|
} = options; |
|
|
|
|
|
if (!currentData || !rawApiResponse) { |
|
|
showAlertDialog(tr('Info'), tr('No data to save, please analyze text first')); |
|
|
return; |
|
|
} |
|
|
|
|
|
const LAST_SAVE_PATH_KEY = 'lastSaveDemoPath'; |
|
|
|
|
|
|
|
|
let result: { name: string; path: string } | null = null; |
|
|
if (presetSaveInfo && presetSaveInfo.name && presetSaveInfo.name.trim()) { |
|
|
const normalizedPath = normalizeFolderPath(presetSaveInfo.path); |
|
|
result = { name: presetSaveInfo.name.trim(), path: normalizedPath }; |
|
|
|
|
|
if (normalizedPath) { |
|
|
localStorage.setItem(LAST_SAVE_PATH_KEY, normalizedPath); |
|
|
} |
|
|
} else { |
|
|
const defaultName = getDefaultDemoName(currentData, textFieldValue, currentFileName); |
|
|
result = await showDemoNameInput(api, defaultName); |
|
|
} |
|
|
|
|
|
if (!result || !result.name || result.name.trim() === '') { |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
const savePath = result.path || '/'; |
|
|
const storage = providedStorage || new ServerStorage(api); |
|
|
|
|
|
|
|
|
const serverController = new DemoStorageController( |
|
|
storage, |
|
|
{ |
|
|
onStart: onSaveStart, |
|
|
onSuccess: async (name, saveResult) => { |
|
|
|
|
|
onSaveSuccess(name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (enableDemo && demoManager && saveResult) { |
|
|
const savedFileName = extractSavedFileName(saveResult, name); |
|
|
const highlightPath = composeDemoFullPath(savePath, savedFileName); |
|
|
|
|
|
if (highlightPath) { |
|
|
|
|
|
try { |
|
|
const success = await demoManager.loadDemoByPath(highlightPath); |
|
|
if (success) { |
|
|
demoManager.highlightDemo(highlightPath); |
|
|
} |
|
|
} catch (err) { |
|
|
console.error('自动加载保存的demo失败:', err); |
|
|
} finally { |
|
|
|
|
|
await demoManager.refresh().catch(refreshErr => { |
|
|
console.error('刷新demo列表失败:', refreshErr); |
|
|
}); |
|
|
} |
|
|
} else { |
|
|
|
|
|
await demoManager.refresh().catch(err => { |
|
|
console.error('刷新demo列表失败:', err); |
|
|
}); |
|
|
} |
|
|
} |
|
|
}, |
|
|
onError: onSaveError, |
|
|
setLoading: setGlobalLoading, |
|
|
showToast, |
|
|
showSuccessToast |
|
|
} |
|
|
); |
|
|
|
|
|
|
|
|
await serverController.save(rawApiResponse, { |
|
|
name: result.name.trim(), |
|
|
path: savePath |
|
|
}); |
|
|
}; |
|
|
|
|
|
|