fix: 前端封装 hook
This commit is contained in:
parent
e2a7c6d9e2
commit
5080ac1e8d
|
|
@ -0,0 +1,233 @@
|
||||||
|
import { useState, useCallback, useRef } from 'react'
|
||||||
|
import { executeCommandWithProgress, ProgressListener } from '../services/tauri'
|
||||||
|
|
||||||
|
export interface ProgressState {
|
||||||
|
step: string
|
||||||
|
progress: number // -1 for indeterminate, 0-100 for percentage
|
||||||
|
message: string
|
||||||
|
details?: any
|
||||||
|
timestamp: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UseProgressCommandOptions {
|
||||||
|
onProgress?: (progress: ProgressState) => void
|
||||||
|
onSuccess?: (result: any) => void
|
||||||
|
onError?: (error: Error) => void
|
||||||
|
autoReset?: boolean // Auto reset state after completion
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UseProgressCommandReturn {
|
||||||
|
// State
|
||||||
|
isExecuting: boolean
|
||||||
|
progress: ProgressState | null
|
||||||
|
result: any
|
||||||
|
error: Error | null
|
||||||
|
logs: string[]
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
execute: (command: string, params: any, eventName: string) => Promise<any>
|
||||||
|
reset: () => void
|
||||||
|
addLog: (message: string) => void
|
||||||
|
clearLogs: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React Hook for executing Tauri commands with progress monitoring
|
||||||
|
*
|
||||||
|
* @param options - Configuration options
|
||||||
|
* @returns Hook state and actions
|
||||||
|
*/
|
||||||
|
export function useProgressCommand(options: UseProgressCommandOptions = {}): UseProgressCommandReturn {
|
||||||
|
const [isExecuting, setIsExecuting] = useState(false)
|
||||||
|
const [progress, setProgress] = useState<ProgressState | null>(null)
|
||||||
|
const [result, setResult] = useState<any>(null)
|
||||||
|
const [error, setError] = useState<Error | null>(null)
|
||||||
|
const [logs, setLogs] = useState<string[]>([])
|
||||||
|
|
||||||
|
const listenerRef = useRef<ProgressListener | null>(null)
|
||||||
|
|
||||||
|
const addLog = useCallback((message: string) => {
|
||||||
|
const timestamp = new Date().toLocaleTimeString()
|
||||||
|
setLogs(prev => [...prev, `[${timestamp}] ${message}`])
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const clearLogs = useCallback(() => {
|
||||||
|
setLogs([])
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const reset = useCallback(() => {
|
||||||
|
setIsExecuting(false)
|
||||||
|
setProgress(null)
|
||||||
|
setResult(null)
|
||||||
|
setError(null)
|
||||||
|
if (options.autoReset !== false) {
|
||||||
|
setLogs([])
|
||||||
|
}
|
||||||
|
}, [options.autoReset])
|
||||||
|
|
||||||
|
const execute = useCallback(async (
|
||||||
|
command: string,
|
||||||
|
params: any,
|
||||||
|
eventName: string
|
||||||
|
): Promise<any> => {
|
||||||
|
try {
|
||||||
|
setIsExecuting(true)
|
||||||
|
setError(null)
|
||||||
|
setResult(null)
|
||||||
|
|
||||||
|
if (options.autoReset !== false) {
|
||||||
|
setProgress(null)
|
||||||
|
setLogs([])
|
||||||
|
}
|
||||||
|
|
||||||
|
addLog(`开始执行命令: ${command}`)
|
||||||
|
|
||||||
|
const onProgress = (progressData: ProgressState) => {
|
||||||
|
setProgress(progressData)
|
||||||
|
addLog(progressData.message)
|
||||||
|
options.onProgress?.(progressData)
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandResult = await executeCommandWithProgress(
|
||||||
|
command,
|
||||||
|
params,
|
||||||
|
eventName,
|
||||||
|
onProgress
|
||||||
|
)
|
||||||
|
|
||||||
|
setResult(commandResult)
|
||||||
|
addLog('命令执行成功')
|
||||||
|
options.onSuccess?.(commandResult)
|
||||||
|
|
||||||
|
return commandResult
|
||||||
|
} catch (err) {
|
||||||
|
const error = err instanceof Error ? err : new Error(String(err))
|
||||||
|
setError(error)
|
||||||
|
addLog(`命令执行失败: ${error.message}`)
|
||||||
|
options.onError?.(error)
|
||||||
|
throw error
|
||||||
|
} finally {
|
||||||
|
setIsExecuting(false)
|
||||||
|
}
|
||||||
|
}, [options, addLog])
|
||||||
|
|
||||||
|
return {
|
||||||
|
// State
|
||||||
|
isExecuting,
|
||||||
|
progress,
|
||||||
|
result,
|
||||||
|
error,
|
||||||
|
logs,
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
execute,
|
||||||
|
reset,
|
||||||
|
addLog,
|
||||||
|
clearLogs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialized hook for template operations
|
||||||
|
*/
|
||||||
|
export function useTemplateProgress(options: UseProgressCommandOptions = {}) {
|
||||||
|
const hook = useProgressCommand(options)
|
||||||
|
|
||||||
|
const batchImport = useCallback(async (sourceFolder: string) => {
|
||||||
|
return hook.execute(
|
||||||
|
'batch_import_templates_with_progress',
|
||||||
|
{ request: { source_folder: sourceFolder } },
|
||||||
|
'template-import-progress'
|
||||||
|
)
|
||||||
|
}, [hook])
|
||||||
|
|
||||||
|
return {
|
||||||
|
...hook,
|
||||||
|
batchImport,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialized hook for AI video operations
|
||||||
|
*/
|
||||||
|
export function useVideoProgress(options: UseProgressCommandOptions = {}) {
|
||||||
|
const hook = useProgressCommand(options)
|
||||||
|
|
||||||
|
const generateVideo = useCallback(async (
|
||||||
|
imagePath: string,
|
||||||
|
prompt: string,
|
||||||
|
outputPath: string
|
||||||
|
) => {
|
||||||
|
return hook.execute(
|
||||||
|
'generate_video_with_progress',
|
||||||
|
{ imagePath, prompt, outputPath },
|
||||||
|
'video-generation-progress'
|
||||||
|
)
|
||||||
|
}, [hook])
|
||||||
|
|
||||||
|
return {
|
||||||
|
...hook,
|
||||||
|
generateVideo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialized hook for data processing operations
|
||||||
|
*/
|
||||||
|
export function useDataProcessingProgress(options: UseProgressCommandOptions = {}) {
|
||||||
|
const hook = useProgressCommand(options)
|
||||||
|
|
||||||
|
const processData = useCallback(async (
|
||||||
|
inputFile: string,
|
||||||
|
outputFile: string,
|
||||||
|
processingType: string
|
||||||
|
) => {
|
||||||
|
return hook.execute(
|
||||||
|
'process_data_with_progress',
|
||||||
|
{ request: { input_file: inputFile, output_file: outputFile, processing_type: processingType } },
|
||||||
|
'data-processing-progress'
|
||||||
|
)
|
||||||
|
}, [hook])
|
||||||
|
|
||||||
|
const batchConvertFiles = useCallback(async (
|
||||||
|
filePaths: string[],
|
||||||
|
outputFormat: string
|
||||||
|
) => {
|
||||||
|
return hook.execute(
|
||||||
|
'batch_convert_files_with_progress',
|
||||||
|
{ filePaths, outputFormat },
|
||||||
|
'file-conversion-progress'
|
||||||
|
)
|
||||||
|
}, [hook])
|
||||||
|
|
||||||
|
return {
|
||||||
|
...hook,
|
||||||
|
processData,
|
||||||
|
batchConvertFiles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialized hook for machine learning operations
|
||||||
|
*/
|
||||||
|
export function useMLProgress(options: UseProgressCommandOptions = {}) {
|
||||||
|
const hook = useProgressCommand(options)
|
||||||
|
|
||||||
|
const trainModel = useCallback(async (
|
||||||
|
datasetPath: string,
|
||||||
|
modelType: string,
|
||||||
|
epochs: number,
|
||||||
|
learningRate: number
|
||||||
|
) => {
|
||||||
|
return hook.execute(
|
||||||
|
'train_model_with_progress',
|
||||||
|
{ request: { dataset_path: datasetPath, model_type: modelType, epochs, learning_rate: learningRate } },
|
||||||
|
'model-training-progress'
|
||||||
|
)
|
||||||
|
}, [hook])
|
||||||
|
|
||||||
|
return {
|
||||||
|
...hook,
|
||||||
|
trainModel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'
|
||||||
import { Upload, FolderOpen, Trash2, Eye, Download, Search, Filter, Grid, List } from 'lucide-react'
|
import { Upload, FolderOpen, Trash2, Eye, Download, Search, Filter, Grid, List } from 'lucide-react'
|
||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { TemplateService } from '../services/tauri'
|
import { TemplateService } from '../services/tauri'
|
||||||
|
import { useTemplateProgress } from '../hooks/useProgressCommand'
|
||||||
|
|
||||||
interface TemplateInfo {
|
interface TemplateInfo {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -19,6 +20,9 @@ interface TemplateInfo {
|
||||||
tags: string[]
|
tags: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Import the progress interface from the hook
|
||||||
|
import type { ProgressState } from '../hooks/useProgressCommand'
|
||||||
|
|
||||||
interface ImportResult {
|
interface ImportResult {
|
||||||
status: boolean
|
status: boolean
|
||||||
msg: string
|
msg: string
|
||||||
|
|
@ -31,26 +35,30 @@ interface ImportResult {
|
||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportProgress {
|
|
||||||
step: string
|
|
||||||
progress: number // -1 for indeterminate, 0-100 for percentage
|
|
||||||
message: string
|
|
||||||
details?: any // Additional details from Python
|
|
||||||
timestamp: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const TemplateManagePage: React.FC = () => {
|
const TemplateManagePage: React.FC = () => {
|
||||||
const [templates, setTemplates] = useState<TemplateInfo[]>([])
|
const [templates, setTemplates] = useState<TemplateInfo[]>([])
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [importing, setImporting] = useState(false)
|
|
||||||
const [searchTerm, setSearchTerm] = useState('')
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid')
|
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid')
|
||||||
const [selectedTemplate, setSelectedTemplate] = useState<TemplateInfo | null>(null)
|
const [selectedTemplate, setSelectedTemplate] = useState<TemplateInfo | null>(null)
|
||||||
const [importResult, setImportResult] = useState<ImportResult | null>(null)
|
|
||||||
const [importProgress, setImportProgress] = useState<ImportProgress | null>(null)
|
|
||||||
const [importLogs, setImportLogs] = useState<string[]>([])
|
|
||||||
const [showImportModal, setShowImportModal] = useState(false)
|
const [showImportModal, setShowImportModal] = useState(false)
|
||||||
|
|
||||||
|
// Use the progress hook for template operations
|
||||||
|
const {
|
||||||
|
isExecuting: importing,
|
||||||
|
progress: importProgress,
|
||||||
|
result: importResult,
|
||||||
|
logs: importLogs,
|
||||||
|
batchImport,
|
||||||
|
reset: resetImport
|
||||||
|
} = useTemplateProgress({
|
||||||
|
onSuccess: async (result) => {
|
||||||
|
if (result.status && result.imported_count > 0) {
|
||||||
|
await loadTemplates() // Reload templates after successful import
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Load templates on component mount
|
// Load templates on component mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
|
|
@ -80,39 +88,11 @@ const TemplateManagePage: React.FC = () => {
|
||||||
const folderResult = await invoke<string>('select_folder')
|
const folderResult = await invoke<string>('select_folder')
|
||||||
if (!folderResult) return
|
if (!folderResult) return
|
||||||
|
|
||||||
// Reset states
|
// Show import modal and start import
|
||||||
setImporting(true)
|
|
||||||
setImportResult(null)
|
|
||||||
setImportProgress(null)
|
|
||||||
setImportLogs([])
|
|
||||||
setShowImportModal(true)
|
setShowImportModal(true)
|
||||||
|
await batchImport(folderResult)
|
||||||
// Progress callback
|
|
||||||
const onProgress = (progress: ImportProgress) => {
|
|
||||||
setImportProgress(progress)
|
|
||||||
setImportLogs(prev => [...prev, `[${new Date().toLocaleTimeString()}] ${progress.message}`])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the new progress-enabled import
|
|
||||||
const result = await TemplateService.batchImportTemplatesWithProgress(folderResult, onProgress)
|
|
||||||
setImportResult(result)
|
|
||||||
|
|
||||||
if (result.status && result.imported_count > 0) {
|
|
||||||
// Reload templates
|
|
||||||
await loadTemplates()
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Import failed:', error)
|
console.error('Import failed:', error)
|
||||||
setImportResult({
|
|
||||||
status: false,
|
|
||||||
msg: error instanceof Error ? error.message : 'Unknown error',
|
|
||||||
imported_count: 0,
|
|
||||||
failed_count: 0,
|
|
||||||
imported_templates: [],
|
|
||||||
failed_templates: []
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
setImporting(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +213,7 @@ const TemplateManagePage: React.FC = () => {
|
||||||
{importResult.failed_count} 个模板导入失败 (点击查看详情)
|
{importResult.failed_count} 个模板导入失败 (点击查看详情)
|
||||||
</summary>
|
</summary>
|
||||||
<div className="mt-2 space-y-1">
|
<div className="mt-2 space-y-1">
|
||||||
{importResult.failed_templates.map((failed, index) => (
|
{importResult.failed_templates.map((failed: any, index: number) => (
|
||||||
<div key={index} className="text-xs text-red-500">
|
<div key={index} className="text-xs text-red-500">
|
||||||
{failed.name}: {failed.error}
|
{failed.name}: {failed.error}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -456,7 +436,7 @@ const TemplateManagePage: React.FC = () => {
|
||||||
{importResult.failed_count} 个模板导入失败 (点击查看详情)
|
{importResult.failed_count} 个模板导入失败 (点击查看详情)
|
||||||
</summary>
|
</summary>
|
||||||
<div className="mt-2 space-y-1">
|
<div className="mt-2 space-y-1">
|
||||||
{importResult.failed_templates.map((failed, index) => (
|
{importResult.failed_templates.map((failed: any, index: number) => (
|
||||||
<div key={index} className="text-xs text-red-500">
|
<div key={index} className="text-xs text-red-500">
|
||||||
{failed.name}: {failed.error}
|
{failed.name}: {failed.error}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,94 @@
|
||||||
|
|
||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
|
|
||||||
|
// Generic progress listener utility
|
||||||
|
export class ProgressListener {
|
||||||
|
private unlisten: (() => void) | null = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a command with progress monitoring
|
||||||
|
* @param command - Tauri command name
|
||||||
|
* @param params - Command parameters
|
||||||
|
* @param eventName - Progress event name to listen to
|
||||||
|
* @param onProgress - Progress callback function
|
||||||
|
* @returns Promise with command result
|
||||||
|
*/
|
||||||
|
static async executeWithProgress<T = any>(
|
||||||
|
command: string,
|
||||||
|
params: any,
|
||||||
|
eventName: string,
|
||||||
|
onProgress?: (progress: any) => void
|
||||||
|
): Promise<T> {
|
||||||
|
const listener = new ProgressListener()
|
||||||
|
return listener.execute(command, params, eventName, onProgress)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a command with progress monitoring (instance method)
|
||||||
|
*/
|
||||||
|
async execute<T = any>(
|
||||||
|
command: string,
|
||||||
|
params: any,
|
||||||
|
eventName: string,
|
||||||
|
onProgress?: (progress: any) => void
|
||||||
|
): Promise<T> {
|
||||||
|
try {
|
||||||
|
// Set up progress listener if callback provided
|
||||||
|
if (onProgress) {
|
||||||
|
await this.startListening(eventName, onProgress)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await invoke(command, params)
|
||||||
|
return JSON.parse(result as string)
|
||||||
|
} finally {
|
||||||
|
// Clean up listener
|
||||||
|
this.stopListening()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to execute command ${command} with progress:`, error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start listening to progress events
|
||||||
|
*/
|
||||||
|
async startListening(eventName: string, onProgress: (progress: any) => void): Promise<void> {
|
||||||
|
const { listen } = await import('@tauri-apps/api/event')
|
||||||
|
this.unlisten = await listen(eventName, (event) => {
|
||||||
|
onProgress(event.payload)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop listening to progress events
|
||||||
|
*/
|
||||||
|
stopListening(): void {
|
||||||
|
if (this.unlisten) {
|
||||||
|
this.unlisten()
|
||||||
|
this.unlisten = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup method (can be called manually if needed)
|
||||||
|
*/
|
||||||
|
cleanup(): void {
|
||||||
|
this.stopListening()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility function for simple one-off progress commands
|
||||||
|
export async function executeCommandWithProgress<T = any>(
|
||||||
|
command: string,
|
||||||
|
params: any,
|
||||||
|
eventName: string,
|
||||||
|
onProgress?: (progress: any) => void
|
||||||
|
): Promise<T> {
|
||||||
|
return ProgressListener.executeWithProgress<T>(command, params, eventName, onProgress)
|
||||||
|
}
|
||||||
|
|
||||||
// Types for video processing
|
// Types for video processing
|
||||||
export interface VideoProcessRequest {
|
export interface VideoProcessRequest {
|
||||||
input_path: string
|
input_path: string
|
||||||
|
|
@ -467,6 +555,85 @@ export class AIVideoService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AI Video generation operations with progress
|
||||||
|
export class AIVideoProgressService {
|
||||||
|
/**
|
||||||
|
* Generate video with progress monitoring
|
||||||
|
*/
|
||||||
|
static async generateVideoWithProgress(
|
||||||
|
imagePath: string,
|
||||||
|
prompt: string,
|
||||||
|
outputPath: string,
|
||||||
|
onProgress?: (progress: any) => void
|
||||||
|
): Promise<any> {
|
||||||
|
return executeCommandWithProgress(
|
||||||
|
'generate_video_with_progress',
|
||||||
|
{ imagePath, prompt, outputPath },
|
||||||
|
'video-generation-progress',
|
||||||
|
onProgress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data processing operations
|
||||||
|
export class DataProcessingService {
|
||||||
|
/**
|
||||||
|
* Process data with progress monitoring
|
||||||
|
*/
|
||||||
|
static async processDataWithProgress(
|
||||||
|
inputFile: string,
|
||||||
|
outputFile: string,
|
||||||
|
processingType: string,
|
||||||
|
onProgress?: (progress: any) => void
|
||||||
|
): Promise<any> {
|
||||||
|
const request = { input_file: inputFile, output_file: outputFile, processing_type: processingType }
|
||||||
|
return executeCommandWithProgress(
|
||||||
|
'process_data_with_progress',
|
||||||
|
{ request },
|
||||||
|
'data-processing-progress',
|
||||||
|
onProgress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Batch convert files with progress monitoring
|
||||||
|
*/
|
||||||
|
static async batchConvertFilesWithProgress(
|
||||||
|
filePaths: string[],
|
||||||
|
outputFormat: string,
|
||||||
|
onProgress?: (progress: any) => void
|
||||||
|
): Promise<any> {
|
||||||
|
return executeCommandWithProgress(
|
||||||
|
'batch_convert_files_with_progress',
|
||||||
|
{ filePaths, outputFormat },
|
||||||
|
'file-conversion-progress',
|
||||||
|
onProgress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Learning operations
|
||||||
|
export class MLService {
|
||||||
|
/**
|
||||||
|
* Train model with progress monitoring
|
||||||
|
*/
|
||||||
|
static async trainModelWithProgress(
|
||||||
|
datasetPath: string,
|
||||||
|
modelType: string,
|
||||||
|
epochs: number,
|
||||||
|
learningRate: number,
|
||||||
|
onProgress?: (progress: any) => void
|
||||||
|
): Promise<any> {
|
||||||
|
const request = { dataset_path: datasetPath, model_type: modelType, epochs, learning_rate: learningRate }
|
||||||
|
return executeCommandWithProgress(
|
||||||
|
'train_model_with_progress',
|
||||||
|
{ request },
|
||||||
|
'model-training-progress',
|
||||||
|
onProgress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Template management operations
|
// Template management operations
|
||||||
export class TemplateService {
|
export class TemplateService {
|
||||||
/**
|
/**
|
||||||
|
|
@ -490,31 +657,13 @@ export class TemplateService {
|
||||||
sourceFolder: string,
|
sourceFolder: string,
|
||||||
onProgress?: (progress: any) => void
|
onProgress?: (progress: any) => void
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
try {
|
|
||||||
const request = { source_folder: sourceFolder }
|
const request = { source_folder: sourceFolder }
|
||||||
|
return executeCommandWithProgress(
|
||||||
// Set up progress listener if callback provided
|
'batch_import_templates_with_progress',
|
||||||
let unlisten: (() => void) | null = null
|
{ request },
|
||||||
if (onProgress) {
|
'template-import-progress',
|
||||||
const { listen } = await import('@tauri-apps/api/event')
|
onProgress
|
||||||
unlisten = await listen('template-import-progress', (event) => {
|
)
|
||||||
onProgress(event.payload)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await invoke('batch_import_templates_with_progress', { request })
|
|
||||||
return JSON.parse(result as string)
|
|
||||||
} finally {
|
|
||||||
// Clean up listener
|
|
||||||
if (unlisten) {
|
|
||||||
unlisten()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to batch import templates with progress:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue