fix: allow workflow saves without previews
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-05-21 11:05:10 +08:00
parent 61da591a5c
commit 2226ab34c7
4 changed files with 50 additions and 66 deletions

View File

@ -3875,22 +3875,6 @@ export function AgentWorkflowSettingsClient({
return;
}
if (changedEntries.some(({ field }) => field === "agentWorkflowUiConfig")) {
const missingPreviewOptions = getAgentWorkflowMissingPreviewOptions(
config.steps || [],
{ enabledOnly: true }
);
if (missingPreviewOptions.length > 0) {
const firstItems = missingPreviewOptions
.slice(0, 3)
.map((item) => `${item.stepPath} / ${item.path}`)
.join(";");
throw new Error(
`当前有 ${missingPreviewOptions.length} 个已启用卡片缺少自己的预览图,请先补图或关闭对应卡片后再保存。${firstItems}`
);
}
}
const conflictedFields = changedEntries
.filter(({ field }) => latestServerSignatures[field] !== baseSignatures[field])
.map(({ field }) => AGENT_WORKFLOW_SETTINGS_FIELD_LABELS[field]);
@ -3968,6 +3952,11 @@ export function AgentWorkflowSettingsClient({
);
return;
}
const savedMissingPreviewOptions = savedWorkflowConfigWasChanged
? getAgentWorkflowMissingPreviewOptions(savedWorkflowConfig.steps || [], {
enabledOnly: true,
})
: [];
const updatedServerState = createAgentWorkflowSettingsStateFromPayload(
updatedSettings || latestSettings
@ -3985,6 +3974,11 @@ export function AgentWorkflowSettingsClient({
.map(({ field }) => AGENT_WORKFLOW_SETTINGS_FIELD_LABELS[field])
.join("、")}`
);
if (savedMissingPreviewOptions.length > 0) {
toast.warning(
`仍有 ${savedMissingPreviewOptions.length} 个启用卡片缺少预览图,前台会自动隐藏这些无图卡片。`
);
}
} catch (error) {
if (error instanceof DOMException && error.name === "AbortError") {
toast.error("保存请求超时,请检查网络或稍后重试");

View File

@ -35,7 +35,6 @@ import {
AGENT_WORKFLOW_UI_CONFIG_KEY,
AGENT_WORKFLOW_PROMPT_FRAGMENT_MAX_LENGTH,
defaultAgentWorkflowUiConfig,
getAgentWorkflowMissingPreviewOptions,
normalizeAgentWorkflowStepOrdering,
normalizeAgentWorkflowUiConfig,
} from "@/lib/agents/workflow-ui-config";
@ -177,29 +176,6 @@ const defaultRealtimeCanvasModeIconConfig: RealtimeCanvasModeIconConfig = {
enhanceLabel: DEFAULT_ENHANCE_CANVAS_MODE_LABEL,
};
function createAgentWorkflowMissingPreviewResponse(
steps: ReturnType<typeof normalizeAgentWorkflowUiConfig>["steps"]
) {
const missingPreviewOptions = getAgentWorkflowMissingPreviewOptions(steps || [], {
enabledOnly: true,
});
if (missingPreviewOptions.length === 0) {
return null;
}
return NextResponse.json(
{
error: `当前有 ${missingPreviewOptions.length} 个已启用卡片缺少自己的预览图,请先补图或关闭对应卡片后再保存。`,
details: missingPreviewOptions.slice(0, 30).map((item) => ({
path: ["agentWorkflowUiConfig", item.stepPath, item.path],
message: `缺少预览图:${item.stepPath} / ${item.path}`,
})),
},
{ status: 400 }
);
}
async function readCanvasFeatureAvailability(valueByKey: Map<string, unknown>) {
const [enabledTripoProviders, enabledWorldlabsProviders] = await Promise.all([
db
@ -2403,12 +2379,6 @@ export async function PUT(request: NextRequest) {
if (agentWorkflowUiConfig !== undefined) {
const normalized = normalizeAgentWorkflowUiConfig(agentWorkflowUiConfig);
const missingPreviewResponse = createAgentWorkflowMissingPreviewResponse(
normalized.steps
);
if (missingPreviewResponse) {
return missingPreviewResponse;
}
await persistSystemSettingWithHistory(
AGENT_WORKFLOW_UI_CONFIG_KEY,
normalized,
@ -3062,12 +3032,6 @@ export async function PUT(request: NextRequest) {
if (agentWorkflowUiConfig !== undefined) {
const normalized = normalizeAgentWorkflowUiConfig(agentWorkflowUiConfig);
const missingPreviewResponse = createAgentWorkflowMissingPreviewResponse(
normalized.steps
);
if (missingPreviewResponse) {
return missingPreviewResponse;
}
await persistSystemSettingWithHistory(
AGENT_WORKFLOW_UI_CONFIG_KEY,
normalized,

View File

@ -389,6 +389,15 @@ function buildPsdLayerPreviewUrl(
});
}
function getPsdLayerPreviewSourceUrl(
layer: Pick<AgentPsdTemplateLayerSlot, "sourceUrl" | "previewUrl">
) {
return (
String(layer.sourceUrl || "").trim() ||
String(layer.previewUrl || "").trim()
);
}
function buildTemplatePreviewFallbackUrls(
template: Pick<AgentPsdTemplate, "previewUrl" | "renderBaseUrl">,
params?: {
@ -2032,7 +2041,7 @@ export function AgentPsdTemplateEditorDialog({
() =>
orderedVisiblePreviewLayers.length === 0 ||
orderedVisiblePreviewLayers.some(
(layer) => !String(layer.sourceUrl || "").trim()
(layer) => !getPsdLayerPreviewSourceUrl(layer)
),
[orderedVisiblePreviewLayers]
);
@ -4102,7 +4111,8 @@ export function AgentPsdTemplateEditorDialog({
const assignedUrl =
effectiveImageAssignments[layer.id];
const layerImageUrl =
assignedUrl || layer.sourceUrl;
assignedUrl ||
getPsdLayerPreviewSourceUrl(layer);
if (!layerImageUrl) {
return null;
}
@ -4206,8 +4216,13 @@ export function AgentPsdTemplateEditorDialog({
resolvedTextColor,
textPositionOffset
);
const layerPreviewSourceUrl =
getPsdLayerPreviewSourceUrl(layer);
if (!shouldUseEditedPreview && layer.sourceUrl) {
if (
!shouldUseEditedPreview &&
layerPreviewSourceUrl
) {
return (
<div
className={`absolute overflow-hidden ${
@ -4249,10 +4264,13 @@ export function AgentPsdTemplateEditorDialog({
alt={layer.layerName}
className="h-full w-full object-fill"
decoding="async"
src={buildPsdLayerPreviewUrl(layer.sourceUrl, {
width: layer.width,
quality: 68,
})}
src={buildPsdLayerPreviewUrl(
layerPreviewSourceUrl,
{
width: layer.width,
quality: 68,
}
)}
/>
</div>
);
@ -4549,8 +4567,10 @@ export function AgentPsdTemplateEditorDialog({
const resolvedTextColor =
effectiveTextColorAssignments[layer.id] ||
layer.textColor;
const layerPreviewSourceUrl =
getPsdLayerPreviewSourceUrl(layer);
const preserveSourceAppearance =
!!layer.sourceUrl &&
!!layerPreviewSourceUrl &&
!hasCustomizedTextLayerAppearance(
layer,
currentValue,
@ -4582,15 +4602,18 @@ export function AgentPsdTemplateEditorDialog({
}}
>
{preserveSourceAppearance &&
layer.sourceUrl ? (
layerPreviewSourceUrl ? (
<img
alt={layer.layerName}
className="pointer-events-none absolute inset-0 h-full w-full object-fill"
decoding="async"
src={buildPsdLayerPreviewUrl(layer.sourceUrl, {
width: layer.width,
quality: 68,
})}
src={buildPsdLayerPreviewUrl(
layerPreviewSourceUrl,
{
width: layer.width,
quality: 68,
}
)}
/>
) : null}
{preserveSourceAppearance ? null : (

View File

@ -858,7 +858,10 @@ export function getAgentWorkflowMissingPreviewOptions(
const label = option.buttonName || option.key;
const pathParts = [...parentPath, label];
if ((!enabledOnly || !disabled) && !hasAgentWorkflowOptionOwnPreview(option)) {
if (
(!enabledOnly || !disabled) &&
!hasAgentWorkflowOptionRenderablePreview(option)
) {
missingOptions.push({
key: option.key,
label,