feat(工作流):支持本地图编排策略包导入导出 (#195)

* docs: define local workflow package mvp

* docs: fix workflow package api contract

* feat: add local workflow package mvp

* feat(workflow): add package API client

* feat(workflow): add package import interface

* feat(workflow): connect package import flow

* fix(workflow): map package validation errors

* fix(workflow): handle import key generation errors

* feat(workflow): localize package import states

* fix(workflow): reset package import modal on open

---------

Co-authored-by: ruanmingchen <“ruanm@chenchen”>
This commit is contained in:
chenchen
2026-07-14 11:28:37 +08:00
committed by GitHub
parent 2e5c1ff286
commit acfacfe1b3
24 changed files with 3154 additions and 3 deletions
+87
View File
@@ -3131,6 +3131,93 @@
"enabledUpdateFailed": "Failed to update enabled status",
"namePlaceholder": "Basic Web scan",
"descriptionPlaceholder": "Optional",
"package": {
"importLocal": "Import local package",
"export": "Export",
"title": "Import local package",
"preflightHint": "Preflight does not modify local workflows",
"stepInspection": "Upload and preflight",
"stepImport": "Resolve conflict and import",
"stepsLabel": "Import steps",
"selectFile": "Choose local package",
"noFile": "No file selected",
"fileHint": "One .csapkg.zip package only, up to 10 MiB.",
"inspect": "Upload and preflight",
"resolutionTitle": "Resolution",
"confirmImport": "Confirm import",
"overwriteTitle": "Overwrite local workflow?",
"overwriteWarning": "This replaces the name, description, graph, and enabled state. Rollback is not available in this release.",
"overwriteCheck": "I confirm overwriting the current local workflow",
"overwriteConfirm": "Overwrite and import",
"errors": {
"fileRequired": "Choose a local workflow package before preflight.",
"fileTooLarge": "The file exceeds the 10 MiB limit. Choose a smaller local package.",
"invalidArchive": "The local package is not a valid Zip archive and cannot be preflighted.",
"unsupportedFormat": "This local package format or version is not supported.",
"invalidManifest": "The local package manifest is invalid and cannot be preflighted.",
"checksumMismatch": "Local package verification failed; the file may be damaged or modified.",
"multipleWorkflows": "This release supports local packages containing one workflow only.",
"workflowInvalid": "The workflow definition in the local package is invalid and cannot be preflighted.",
"inspectionNotFound": "The preflight record no longer exists. Upload and preflight again.",
"inspectionExpired": "The preflight has expired. Upload and preflight again.",
"inspectionConsumed": "This preflight has already been imported and cannot be reused.",
"conflictChanged": "The local workflow changed after preflight. Run preflight again before importing.",
"idConflict": "The selected resolution no longer matches the current conflict state. Run preflight again.",
"invalidAction": "The import resolution is invalid. Choose it again.",
"invalidRenameId": "Enter an available new workflow ID.",
"overwriteConfirmationRequired": "Confirm the overwrite before replacing the local workflow.",
"idempotencyKeyRequired": "The browser cannot create an import request identifier. Refresh and try again.",
"idempotencyKeyReused": "The import request state is invalid. Run preflight again and retry.",
"importFailed": "Import failed; the local workflow was not changed.",
"exportFailed": "Export failed. Try again later.",
"workflowNotFound": "The workflow was not found and cannot be exported.",
"generic": "The operation was not completed. Try again later.",
"serviceUnavailable": "The import service is not ready. Refresh the page and try again."
},
"conflict": {
"identical": "A local workflow with the same ID and content was found; import will be skipped.",
"idConflict": "A local workflow with the same ID but different content was found. The local version will be kept by default.",
"none": "No local workflow with the same ID was found. A new workflow can be created."
},
"summary": {
"workflowName": "Workflow name",
"unnamedWorkflow": "Untitled workflow",
"sourceId": "Source workflow ID",
"sourceRevision": "Source revision",
"graphSize": "Graph size",
"graphSizeValue": "{{nodes}} nodes · {{edges}} edges",
"contentHash": "Content hash",
"expiresAt": "Preflight expires"
},
"resolution": {
"needInspection": "Choose a local package and complete preflight first.",
"createHint": "Import will create a new local workflow.",
"identicalHint": "The same content already exists. No duplicate import is needed.",
"keepExisting": "Keep local version",
"keepExistingHint": "Do not change the current local workflow; the import record is retained.",
"revealRiskChoices": "Change resolution",
"overwrite": "Overwrite local version",
"overwriteHint": "Replace the name, description, graph, and enabled state; a second confirmation is required.",
"rename": "Save under a new ID",
"renameHint": "Keep the current local workflow and create a copy under a new ID.",
"newWorkflowId": "New workflow ID",
"newWorkflowIdPlaceholder": "For example: web-scan-basic-copy",
"continueOverwrite": "Continue to overwrite confirmation",
"confirmRename": "Confirm save as new ID",
"confirmCreate": "Confirm create",
"confirmComplete": "Confirm completion"
},
"result": {
"created": "Import completed: a new local workflow was created.",
"overwritten": "Import completed: the local workflow was overwritten.",
"renamed": "Import completed: a local workflow was created under the new ID.",
"keptExisting": "The local workflow was kept; no changes were made.",
"skippedIdentical": "The same local content already exists; import was skipped.",
"complete": "Import completed.",
"completedAction": "Import completed"
},
"exportSelectSaved": "Choose a saved workflow before exporting."
},
"connect": "Connect",
"connecting": "Connecting",
"deleteSelected": "Delete selected",
+87
View File
@@ -3119,6 +3119,93 @@
"enabledUpdateFailed": "更新启用状态失败",
"namePlaceholder": "基础 Web 扫描",
"descriptionPlaceholder": "可选",
"package": {
"importLocal": "导入本地包",
"export": "导出",
"title": "导入本地包",
"preflightHint": "预检不会修改本地工作流",
"stepInspection": "上传与预检",
"stepImport": "处理冲突与导入",
"stepsLabel": "导入步骤",
"selectFile": "选择本地包",
"noFile": "未选择文件",
"fileHint": "仅支持单个 .csapkg.zip,文件不得超过 10 MiB。",
"inspect": "上传并预检",
"resolutionTitle": "处理方式",
"confirmImport": "确认导入",
"overwriteTitle": "确认覆盖本地工作流?",
"overwriteWarning": "覆盖将替换名称、描述、图定义和启用状态。本期不提供回滚。",
"overwriteCheck": "我已确认覆盖当前本地工作流",
"overwriteConfirm": "确认覆盖并导入",
"errors": {
"fileRequired": "请选择本地图编排包后再预检。",
"fileTooLarge": "文件超过 10 MiB 限制,请选择更小的本地包。",
"invalidArchive": "本地包不是有效的 Zip 文件,无法完成预检。",
"unsupportedFormat": "本地包格式或版本不受支持。",
"invalidManifest": "本地包清单无效,无法完成预检。",
"checksumMismatch": "本地包校验失败,文件可能已损坏或被修改。",
"multipleWorkflows": "本期仅支持导入包含一个工作流的本地包。",
"workflowInvalid": "本地包中的工作流定义无效,无法完成预检。",
"inspectionNotFound": "预检记录不存在,请重新上传并预检。",
"inspectionExpired": "预检已过期,请重新上传并预检。",
"inspectionConsumed": "该预检已完成导入,不能重复使用。",
"conflictChanged": "本地工作流在预检后发生变化,请重新预检后再导入。",
"idConflict": "当前处理方式与最新冲突状态不匹配,请重新预检。",
"invalidAction": "导入处理方式无效,请重新选择。",
"invalidRenameId": "请输入可用的新工作流 ID。",
"overwriteConfirmationRequired": "请勾选确认后再覆盖本地工作流。",
"idempotencyKeyRequired": "浏览器无法生成导入请求标识,请刷新页面后重试。",
"idempotencyKeyReused": "导入请求状态异常,请重新预检后再试。",
"importFailed": "导入失败,本地工作流未被修改。",
"exportFailed": "导出失败,请稍后重试。",
"workflowNotFound": "未找到该工作流,无法导出。",
"generic": "操作未完成,请稍后重试。",
"serviceUnavailable": "导入服务尚未准备好,请刷新页面后重试。"
},
"conflict": {
"identical": "检测到同 ID 且内容相同的本地工作流;本次将跳过导入。",
"idConflict": "检测到同 ID 但内容不同的本地工作流。默认保留本地版本。",
"none": "未发现同 ID 的本地工作流,可创建导入。"
},
"summary": {
"workflowName": "工作流名称",
"unnamedWorkflow": "未命名工作流",
"sourceId": "源工作流 ID",
"sourceRevision": "源版本",
"graphSize": "图规模",
"graphSizeValue": "{{nodes}} 个节点 · {{edges}} 条连线",
"contentHash": "内容摘要",
"expiresAt": "预检有效期"
},
"resolution": {
"needInspection": "请先选择本地包并完成预检。",
"createHint": "导入后会创建一个新的本地工作流。",
"identicalHint": "内容已经存在,无需重复导入。",
"keepExisting": "保留本地版本",
"keepExistingHint": "不修改当前本地工作流;导入记录会保留。",
"revealRiskChoices": "更改处理方式",
"overwrite": "覆盖本地版本",
"overwriteHint": "替换名称、描述、图定义和启用状态;需要再次确认。",
"rename": "另存为新 ID",
"renameHint": "保留当前本地工作流,并以新的 ID 创建副本。",
"newWorkflowId": "新的工作流 ID",
"newWorkflowIdPlaceholder": "例如:web-scan-basic-copy",
"continueOverwrite": "继续确认覆盖",
"confirmRename": "确认另存",
"confirmCreate": "确认创建",
"confirmComplete": "确认完成"
},
"result": {
"created": "导入成功,已创建新的本地工作流。",
"overwritten": "导入成功,已覆盖本地工作流。",
"renamed": "导入成功,已按新 ID 创建本地工作流。",
"keptExisting": "已保留本地工作流,未写入任何更改。",
"skippedIdentical": "本地已存在相同内容,已跳过导入。",
"complete": "导入已完成。",
"completedAction": "导入已完成"
},
"exportSelectSaved": "请先选择已保存的工作流后再导出。"
},
"connect": "连线",
"connecting": "连线中",
"deleteSelected": "删除选中",