- flows: writeFlowFile 覆盖写加固(清只读属性->删除后 rename->覆盖写), 外部复制导入的只读任务文件此前导致 flows:save EPERM 崩溃 - flows: exportFlowToPath/importFlowFromPath, 分享文件为单个 FlowDefinition JSON(.rpaflow.json); 导入校验 schemaVersion/nodes/edges, id 冲突时生成 imported_ 前缀新 id 绝不覆盖既有任务 - IPC: flows:export 弹保存对话框 / flows:import 弹多选打开对话框, 失败文件逐个汇报不阻塞其余 - preload: flows.export/flows.import; shared: FlowsImportResult 类型 - TasksPage: 头部「导入任务」按钮 + 每行「分享」按钮; App 接线与 toast - 测试: 导出/导入往返、id 冲突、非法文件原因、只读覆盖共 4 例(7/7 绿)
139 lines
3.0 KiB
TypeScript
139 lines
3.0 KiB
TypeScript
/**
|
||
* 共享类型:宿主专属模型定义 + 领域类型 re-export。
|
||
*
|
||
* 领域类型(Catalog/Flow/RunError/RunEvent 等)已迁入 @rpa/core(packages/rpa-core/src/types.ts),
|
||
* 此处 type-only re-export 保持既有 import 路径(@shared/types)不变,全仓单一来源、无复制。
|
||
*/
|
||
|
||
export type {
|
||
CatalogWidget,
|
||
CatalogField,
|
||
CatalogOutput,
|
||
CatalogComponent,
|
||
CatalogGroup,
|
||
Catalog,
|
||
FlowVariable,
|
||
FlowNodeOptions,
|
||
FlowNode,
|
||
FlowEdge,
|
||
FlowDefinition,
|
||
RunError,
|
||
RunEvent
|
||
} from "@rpa/core";
|
||
|
||
import type { FlowDefinition, RunError } from "@rpa/core";
|
||
|
||
export interface FlowSaveOptions {
|
||
/** 编辑器加载任务时磁盘上的 updatedAt,用于外部修改冲突检测 */
|
||
expectedUpdatedAt?: string;
|
||
/** 为 true 时跳过冲突检测,强制覆盖磁盘 */
|
||
force?: boolean;
|
||
}
|
||
|
||
export type FlowSaveResult =
|
||
| { conflict: false; flow: FlowDefinition }
|
||
| { conflict: true; diskFlow: FlowDefinition };
|
||
|
||
/** 批量导入任务的结果:成功与失败分开汇报,单文件失败不阻塞其余 */
|
||
export interface FlowsImportResult {
|
||
imported: FlowSummary[];
|
||
failed: Array<{ file: string; reason: string }>;
|
||
}
|
||
export interface FlowSummary {
|
||
id: string;
|
||
name: string;
|
||
updatedAt: string;
|
||
nodeCount: number;
|
||
enabled?: boolean;
|
||
triggerLabel?: string;
|
||
lastRunAt?: string;
|
||
lastRunStatus?: "succeeded" | "failed" | "cancelled" | "never";
|
||
lastRunDurationMs?: number;
|
||
lastRunError?: string;
|
||
}
|
||
|
||
export interface AppInfo {
|
||
version: string;
|
||
electron: string;
|
||
chrome: string;
|
||
node: string;
|
||
userData: string;
|
||
catalogPath: string;
|
||
packaged: boolean;
|
||
fixtureUrl?: string;
|
||
}
|
||
|
||
export interface AiServiceConfig {
|
||
baseUrl: string;
|
||
apiKey: string;
|
||
model: string;
|
||
/** 桌面 AI 拾取使用的视觉模型;留空时复用 model。 */
|
||
visionModel?: string;
|
||
}
|
||
|
||
export interface AppSettings {
|
||
browserElementWaitMs: number;
|
||
aiConfig: AiServiceConfig;
|
||
}
|
||
|
||
export interface ElementPickResult {
|
||
selector: string;
|
||
tag: string;
|
||
id?: string;
|
||
className?: string;
|
||
name?: string;
|
||
type?: string;
|
||
placeholder?: string;
|
||
label?: string;
|
||
text?: string;
|
||
value?: string;
|
||
url: string;
|
||
}
|
||
|
||
export interface RunNodeState {
|
||
nodeId: string;
|
||
status: "idle" | "running" | "succeeded" | "failed" | "skipped" | "cancelled";
|
||
startedAt?: string;
|
||
finishedAt?: string;
|
||
durationMs?: number;
|
||
output?: unknown;
|
||
error?: RunError;
|
||
evidence?: string[];
|
||
attempt?: number;
|
||
}
|
||
|
||
export interface VisionLabSource {
|
||
id: string;
|
||
kind: "window" | "screen";
|
||
name: string;
|
||
thumbnail: string;
|
||
icon?: string;
|
||
}
|
||
|
||
export interface VisionLabBox {
|
||
x: number;
|
||
y: number;
|
||
width: number;
|
||
height: number;
|
||
category: string;
|
||
confidence: number;
|
||
}
|
||
|
||
export interface VisionLabDetectRequest {
|
||
sourceId: string;
|
||
modelPath?: string;
|
||
scoreThreshold?: number;
|
||
iouThreshold?: number;
|
||
}
|
||
|
||
export interface VisionLabDetection {
|
||
image: string;
|
||
width: number;
|
||
height: number;
|
||
boxes: VisionLabBox[];
|
||
captureMs: number;
|
||
detectMs: number;
|
||
modelPath: string;
|
||
sourceName: string;
|
||
}
|