|
|
|
|
|
|
|
|
|
|
|
|
|
|
import type { AnalysisData } from '../api/GLTR_API'; |
|
|
import type { IDemoStorage, SaveOptions, SaveResult } from '../storage/demoStorage'; |
|
|
import { showConfirmDialog, showAlertDialog } from '../ui/dialog'; |
|
|
import { tr, trf } from '../lang/i18n-lite'; |
|
|
|
|
|
export interface StorageCallbacks { |
|
|
onStart?: () => void; |
|
|
onSuccess?: (name?: string, result?: SaveResult) => void; |
|
|
onError?: (error: Error) => void; |
|
|
setLoading?: (loading: boolean) => void; |
|
|
showToast?: (message: string, type: 'success' | 'error') => void; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
showSuccessToast?: boolean; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class DemoStorageController { |
|
|
constructor( |
|
|
private storage: IDemoStorage, |
|
|
private callbacks: StorageCallbacks = {} |
|
|
) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async save(data: AnalysisData, options: SaveOptions): Promise<SaveResult | null> { |
|
|
const { onStart, onSuccess, onError, setLoading, showToast, showSuccessToast = true } = this.callbacks; |
|
|
|
|
|
onStart?.(); |
|
|
setLoading?.(true); |
|
|
|
|
|
try { |
|
|
const result = await this._doSave(data, options, false); |
|
|
setLoading?.(false); |
|
|
|
|
|
if (result) { |
|
|
onSuccess?.(options.name, result); |
|
|
|
|
|
if (showSuccessToast) { |
|
|
const hint = this.storage.type === 'local' ? tr('Downloaded to local') : tr('Upload successful'); |
|
|
showToast?.(`Demo "${options.name}" ${hint}!`, 'success'); |
|
|
} |
|
|
} |
|
|
|
|
|
return result; |
|
|
} catch (error) { |
|
|
setLoading?.(false); |
|
|
const err = error instanceof Error ? error : new Error(String(error)); |
|
|
onError?.(err); |
|
|
|
|
|
|
|
|
showAlertDialog(tr('Error'), trf('Save failed: {message}', { message: err.message })); |
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private async _doSave( |
|
|
data: AnalysisData, |
|
|
options: SaveOptions, |
|
|
overwrite: boolean |
|
|
): Promise<SaveResult | null> { |
|
|
const result = await this.storage.save(data, { ...options, overwrite }); |
|
|
|
|
|
|
|
|
if (!result.success && result.exists && this.storage.type === 'server') { |
|
|
return new Promise((resolve) => { |
|
|
this.callbacks.setLoading?.(false); |
|
|
showConfirmDialog( |
|
|
tr('File already exists'), |
|
|
trf('File "{name}.json" already exists, overwrite?', { name: options.name }), |
|
|
async () => { |
|
|
this.callbacks.setLoading?.(true); |
|
|
const saved = await this._doSave(data, options, true); |
|
|
resolve(saved); |
|
|
}, |
|
|
() => { |
|
|
this.callbacks.onError?.(new Error(tr('User cancelled save'))); |
|
|
resolve(null); |
|
|
}, |
|
|
tr('Overwrite'), |
|
|
tr('Cancel') |
|
|
); |
|
|
}); |
|
|
} |
|
|
|
|
|
if (!result.success) { |
|
|
throw new Error(result.message || 'Save failed'); |
|
|
} |
|
|
|
|
|
return result; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async load(path?: string): Promise<AnalysisData | null> { |
|
|
const { onStart, onSuccess, onError, setLoading } = this.callbacks; |
|
|
|
|
|
onStart?.(); |
|
|
setLoading?.(true); |
|
|
|
|
|
try { |
|
|
const result = await this.storage.load(path); |
|
|
setLoading?.(false); |
|
|
|
|
|
if (result.success && result.data) { |
|
|
onSuccess?.(); |
|
|
return result.data; |
|
|
} else { |
|
|
|
|
|
if (result.message) { |
|
|
const err = new Error(result.message || 'Load failed'); |
|
|
onError?.(err); |
|
|
showAlertDialog(tr('Error'), tr(err.message)); |
|
|
} |
|
|
return null; |
|
|
} |
|
|
} catch (error) { |
|
|
setLoading?.(false); |
|
|
const err = error instanceof Error ? error : new Error(String(error)); |
|
|
onError?.(err); |
|
|
showAlertDialog(tr('Error'), trf('Load failed: {message}', { message: err.message })); |
|
|
return null; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|