fix: support global workflow card blocking
This commit is contained in:
parent
1768413eca
commit
04428bf6b2
@ -234,6 +234,27 @@ function collectWorkflowOptionRelations(
|
||||
});
|
||||
}
|
||||
|
||||
function collectWorkflowOptionRelationsFromSteps(
|
||||
steps: AgentWorkflowStepUiConfig[]
|
||||
): Array<{
|
||||
key: string;
|
||||
label: string;
|
||||
depth: number;
|
||||
stepKey: string;
|
||||
stepTitle: string;
|
||||
}> {
|
||||
return flattenAgentWorkflowSteps(steps).flatMap(({ step }) =>
|
||||
collectWorkflowOptionRelations(step.options || []).map((item) => ({
|
||||
...item,
|
||||
label: `${step.title} / ${item.label}`,
|
||||
stepKey: step.key,
|
||||
stepTitle: step.title,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
type WorkflowOptionRelation = ReturnType<typeof collectWorkflowOptionRelationsFromSteps>[number];
|
||||
|
||||
function updateWorkflowOptionTree(
|
||||
options: AgentWorkflowOptionUiConfig[],
|
||||
optionKey: string,
|
||||
@ -1234,20 +1255,12 @@ export function AgentWorkflowSettingsClient({
|
||||
(left, right) => left.sortOrder - right.sortOrder
|
||||
);
|
||||
const canAddChild = depth < AGENT_WORKFLOW_MAX_OPTION_DEPTH;
|
||||
const optionRelations = collectWorkflowOptionRelations(step.options || []);
|
||||
const optionRelations = collectWorkflowOptionRelationsFromSteps(config.steps || []);
|
||||
const optionLookup = new Map(optionRelations.map((item) => [item.key, item] as const));
|
||||
const blockedCandidates = optionRelations.filter((item) => item.key !== option.key);
|
||||
const selectedBlockedItems = (option.blockedOptionKeys || [])
|
||||
.map((blockedKey) => optionLookup.get(blockedKey))
|
||||
.filter(
|
||||
(
|
||||
item
|
||||
): item is {
|
||||
key: string;
|
||||
label: string;
|
||||
depth: number;
|
||||
} => Boolean(item)
|
||||
);
|
||||
.filter((item): item is WorkflowOptionRelation => Boolean(item));
|
||||
|
||||
return (
|
||||
<div key={option.key} className={cn("space-y-4", depth > 1 && "pl-4 sm:pl-6")}>
|
||||
@ -1367,7 +1380,7 @@ export function AgentWorkflowSettingsClient({
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">互斥卡片限制</Label>
|
||||
<p className="text-[11px] leading-5 text-muted-foreground">
|
||||
选中当前卡片后,下方指定的其它卡片会在前台变灰并不可选。
|
||||
选中当前卡片后,下方指定的其它卡片会在前台变灰并不可选。可跨所有流程节点,并覆盖各节点下的所有层级子卡片。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -1453,7 +1466,7 @@ export function AgentWorkflowSettingsClient({
|
||||
})
|
||||
) : (
|
||||
<div className="px-2 py-3 text-center text-xs text-muted-foreground">
|
||||
当前步骤下没有其他可限制卡片
|
||||
当前工作流下没有其他可限制卡片
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
defaultAgentWorkflowUiConfig,
|
||||
flattenAgentWorkflowSteps,
|
||||
flattenVisibleAgentWorkflowSteps,
|
||||
getAgentWorkflowBlockedOptionKeys,
|
||||
getAgentWorkflowBlockedOptionKeysForSelections,
|
||||
getAgentWorkflowBrandStoreEntries,
|
||||
getAgentWorkflowPriceBandOptions,
|
||||
getAgentWorkflowSelectedOptionPath,
|
||||
@ -405,18 +405,16 @@ export function AgentWorkflowPanelDarkV2({
|
||||
]);
|
||||
return Object.fromEntries(entries) as Record<string, string>;
|
||||
}, [resolvedConfig.steps, selections]);
|
||||
const blockedOptionKeyMap = useMemo(() => {
|
||||
const entries = flattenAgentWorkflowSteps(resolvedConfig.steps).map(({ step }) => [
|
||||
step.key,
|
||||
const blockedOptionKeys = useMemo(
|
||||
() =>
|
||||
new Set(
|
||||
getAgentWorkflowBlockedOptionKeys({
|
||||
step,
|
||||
selectionValue: selections[step.key],
|
||||
getAgentWorkflowBlockedOptionKeysForSelections({
|
||||
config: resolvedConfig,
|
||||
selections,
|
||||
})
|
||||
),
|
||||
] as const);
|
||||
return new Map(entries);
|
||||
}, [resolvedConfig.steps, selections]);
|
||||
[resolvedConfig, selections]
|
||||
);
|
||||
const [autoAdvanceNotice, setAutoAdvanceNotice] = useState<{
|
||||
completedStepTitle: string;
|
||||
completedSummary: string;
|
||||
@ -571,7 +569,6 @@ export function AgentWorkflowPanelDarkV2({
|
||||
const currentSelectedKey = selectedPathKeys[depth - 1] || "";
|
||||
const currentSelectedOption =
|
||||
options.find((option) => option.key === currentSelectedKey) || null;
|
||||
const blockedKeys = blockedOptionKeyMap.get(step.key) || new Set<string>();
|
||||
const visibleChildren = getEnabledAgentWorkflowOptionTree(
|
||||
currentSelectedOption?.children || []
|
||||
);
|
||||
@ -593,7 +590,7 @@ export function AgentWorkflowPanelDarkV2({
|
||||
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
|
||||
{options.map((option, optionIndex) => {
|
||||
const isDisabled =
|
||||
currentSelectedKey !== option.key && blockedKeys.has(option.key);
|
||||
currentSelectedKey !== option.key && blockedOptionKeys.has(option.key);
|
||||
|
||||
return (
|
||||
<StepOptionCard
|
||||
@ -857,11 +854,9 @@ export function AgentWorkflowPanelDarkV2({
|
||||
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
|
||||
{activeEmbeddedOptionLevel.options.map((option, optionIndex) => {
|
||||
const currentSelectedKey = activeEmbeddedOptionLevel.selectedKey;
|
||||
const blockedKeys =
|
||||
blockedOptionKeyMap.get(activeEmbeddedStepEntry.step.key) ||
|
||||
new Set<string>();
|
||||
const isDisabled =
|
||||
currentSelectedKey !== option.key && blockedKeys.has(option.key);
|
||||
currentSelectedKey !== option.key &&
|
||||
blockedOptionKeys.has(option.key);
|
||||
const nextChildren = getEnabledAgentWorkflowOptionTree(
|
||||
option.children || []
|
||||
);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type {
|
||||
AgentWorkflowBrandStoreEntry,
|
||||
AgentWorkflowOptionUiConfig,
|
||||
AgentWorkflowStepKey,
|
||||
AgentWorkflowStepUiConfig,
|
||||
AgentWorkflowUiConfig,
|
||||
} from "@/types/agent";
|
||||
@ -290,6 +291,16 @@ export function countAgentWorkflowOptionTree(
|
||||
return flattenAgentWorkflowOptionTree(options).length;
|
||||
}
|
||||
|
||||
function collectWorkflowOptionKeySetFromSteps(
|
||||
steps: AgentWorkflowStepUiConfig[]
|
||||
): Set<string> {
|
||||
return new Set(
|
||||
flattenAgentWorkflowSteps(steps).flatMap(({ step }) =>
|
||||
flattenAgentWorkflowOptionTree(step.options || []).map(({ option }) => option.key)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function normalizeAgentWorkflowOptionOrdering(
|
||||
options: AgentWorkflowOptionUiConfig[]
|
||||
): AgentWorkflowOptionUiConfig[] {
|
||||
@ -385,6 +396,17 @@ function sanitizeBlockedOptionTree(
|
||||
}));
|
||||
}
|
||||
|
||||
function sanitizeBlockedWorkflowStepTree(
|
||||
steps: AgentWorkflowStepUiConfig[],
|
||||
validKeys: Set<string>
|
||||
): AgentWorkflowStepUiConfig[] {
|
||||
return steps.map((step) => ({
|
||||
...step,
|
||||
options: sanitizeBlockedOptionTree(step.options || [], validKeys),
|
||||
children: sanitizeBlockedWorkflowStepTree(step.children || [], validKeys),
|
||||
}));
|
||||
}
|
||||
|
||||
export function normalizeAgentWorkflowUiConfig(value: unknown): AgentWorkflowUiConfig {
|
||||
const raw =
|
||||
value && typeof value === "object" && !Array.isArray(value)
|
||||
@ -569,8 +591,6 @@ export function normalizeAgentWorkflowUiConfig(value: unknown): AgentWorkflowUiC
|
||||
normalizeOption(option, optionIndex, stepKey, usedOptionKeys, defaultOptions, 1)
|
||||
)
|
||||
.sort((left, right) => left.sortOrder - right.sortOrder);
|
||||
const sanitizedOptions = sanitizeBlockedOptionTree(options);
|
||||
|
||||
const hasRawChildren = Array.isArray(stepRecord?.children);
|
||||
const rawChildren = hasRawChildren ? (stepRecord?.children as unknown[]) : [];
|
||||
const defaultChildren =
|
||||
@ -588,7 +608,7 @@ export function normalizeAgentWorkflowUiConfig(value: unknown): AgentWorkflowUiC
|
||||
description: normalizeText(stepRecord?.description, 300) || fallbackDescription,
|
||||
enabled: normalizeBoolean(stepRecord?.enabled, defaultStep?.enabled ?? true),
|
||||
sortOrder: normalizeNumber(stepRecord?.sortOrder, defaultStep?.sortOrder ?? stepIndex),
|
||||
options: sanitizedOptions,
|
||||
options,
|
||||
children:
|
||||
depth < AGENT_WORKFLOW_MAX_TREE_DEPTH
|
||||
? childSource
|
||||
@ -601,6 +621,8 @@ export function normalizeAgentWorkflowUiConfig(value: unknown): AgentWorkflowUiC
|
||||
const normalizedSteps = sourceSteps
|
||||
.map((item, stepIndex) => normalizeStep(item, stepIndex, 1))
|
||||
.sort((left, right) => left.sortOrder - right.sortOrder);
|
||||
const validOptionKeys = collectWorkflowOptionKeySetFromSteps(normalizedSteps);
|
||||
const sanitizedSteps = sanitizeBlockedWorkflowStepTree(normalizedSteps, validOptionKeys);
|
||||
|
||||
return {
|
||||
inputOptions: {
|
||||
@ -617,7 +639,7 @@ export function normalizeAgentWorkflowUiConfig(value: unknown): AgentWorkflowUiC
|
||||
priceBands: normalizedPriceBands,
|
||||
brandStoreEntries: fallbackBrandStoreEntries,
|
||||
},
|
||||
steps: normalizedSteps,
|
||||
steps: sanitizedSteps,
|
||||
};
|
||||
}
|
||||
|
||||
@ -691,6 +713,28 @@ export function getAgentWorkflowBlockedOptionKeys(params: {
|
||||
);
|
||||
}
|
||||
|
||||
export function getAgentWorkflowBlockedOptionKeysForSelections(params: {
|
||||
config?: AgentWorkflowUiConfig | null;
|
||||
selections: Partial<Record<AgentWorkflowStepKey, string>>;
|
||||
}) {
|
||||
const config = params.config || defaultAgentWorkflowUiConfig;
|
||||
const visibleSteps = flattenVisibleAgentWorkflowSteps(
|
||||
getEnabledAgentWorkflowStepTree(Array.isArray(config.steps) ? config.steps : []),
|
||||
params.selections
|
||||
).map(({ step }) => step);
|
||||
|
||||
return Array.from(
|
||||
new Set(
|
||||
visibleSteps.flatMap((step) =>
|
||||
getAgentWorkflowBlockedOptionKeys({
|
||||
step,
|
||||
selectionValue: params.selections[step.key],
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function isAgentWorkflowStepSelectionComplete(params: {
|
||||
step: AgentWorkflowStepUiConfig;
|
||||
selectionValue?: string | null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user