fix: restore rule detail dependencies
This commit is contained in:
@@ -185,6 +185,28 @@ function fallbackDependencyOption(value: string, optionMap?: Map<string, Depende
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveRuleDependencies(
|
||||||
|
rule: RuleSummary | undefined,
|
||||||
|
rulesById: Map<string, RuleSummary>,
|
||||||
|
visited = new Set<string>(),
|
||||||
|
): string[] {
|
||||||
|
if (!rule) return [];
|
||||||
|
const key = rule.ruleId || rule.id;
|
||||||
|
if (visited.has(key)) return [];
|
||||||
|
visited.add(key);
|
||||||
|
|
||||||
|
const merged = new Set<string>((rule.dependencies || []).filter(Boolean));
|
||||||
|
|
||||||
|
(rule.subRuleIds || []).forEach((ruleId) => {
|
||||||
|
const referenced = rulesById.get(ruleId);
|
||||||
|
resolveRuleDependencies(referenced, rulesById, visited).forEach((dependency) => {
|
||||||
|
if (dependency) merged.add(dependency);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(merged);
|
||||||
|
}
|
||||||
|
|
||||||
function makeId(prefix: string): string {
|
function makeId(prefix: string): string {
|
||||||
return `${prefix}-${Date.now()}`;
|
return `${prefix}-${Date.now()}`;
|
||||||
}
|
}
|
||||||
@@ -571,29 +593,36 @@ export default function RulesTestDetail() {
|
|||||||
'ai_rule',
|
'ai_rule',
|
||||||
'rule_group'
|
'rule_group'
|
||||||
]), [rules]);
|
]), [rules]);
|
||||||
|
const rulesById = useMemo(() => new Map(rules.map(rule => [rule.ruleId || rule.id, rule])), [rules]);
|
||||||
const selectedDependencyOptions = useMemo(() => {
|
const selectedDependencyOptions = useMemo(() => {
|
||||||
return ruleDraft.dependencies.map(value => dependencyOptionMap.get(value) || fallbackDependencyOption(value, dependencyOptionMap));
|
return ruleDraft.dependencies.map(value => dependencyOptionMap.get(value) || fallbackDependencyOption(value, dependencyOptionMap));
|
||||||
}, [dependencyOptionMap, ruleDraft.dependencies]);
|
}, [dependencyOptionMap, ruleDraft.dependencies]);
|
||||||
|
const resolvedCurrentDependencies = useMemo(() => {
|
||||||
|
return resolveRuleDependencies(currentRule, rulesById);
|
||||||
|
}, [currentRule, rulesById]);
|
||||||
|
const currentRuleWithResolvedDependencies = useMemo(() => (
|
||||||
|
currentRule ? { ...currentRule, dependencies: resolvedCurrentDependencies } : undefined
|
||||||
|
), [currentRule, resolvedCurrentDependencies]);
|
||||||
const currentDependencyRows = useMemo(() => {
|
const currentDependencyRows = useMemo(() => {
|
||||||
return (currentRule?.dependencies || []).map(value => dependencyOptionMap.get(value) || fallbackDependencyOption(value, dependencyOptionMap));
|
return resolvedCurrentDependencies.map(value => dependencyOptionMap.get(value) || fallbackDependencyOption(value, dependencyOptionMap));
|
||||||
}, [currentRule, dependencyOptionMap]);
|
}, [dependencyOptionMap, resolvedCurrentDependencies]);
|
||||||
const currentRuleFields = useMemo(
|
const currentRuleFields = useMemo(
|
||||||
() => fields.filter((field) => matchesCurrentRuleDependency(currentRule, [field.name])),
|
() => fields.filter((field) => matchesCurrentRuleDependency(currentRuleWithResolvedDependencies, [field.name])),
|
||||||
[currentRule, fields],
|
[currentRuleWithResolvedDependencies, fields],
|
||||||
);
|
);
|
||||||
const currentRuleSubDocuments = useMemo(
|
const currentRuleSubDocuments = useMemo(
|
||||||
() => subDocuments.filter((document) => matchesCurrentRuleDependency(currentRule, [document.name, document.id])),
|
() => subDocuments.filter((document) => matchesCurrentRuleDependency(currentRuleWithResolvedDependencies, [document.name, document.id])),
|
||||||
[currentRule, subDocuments],
|
[currentRuleWithResolvedDependencies, subDocuments],
|
||||||
);
|
);
|
||||||
const currentRuleVisualElements = useMemo(
|
const currentRuleVisualElements = useMemo(
|
||||||
() => visualElements.filter((item) => matchesCurrentRuleDependency(currentRule, [
|
() => visualElements.filter((item) => matchesCurrentRuleDependency(currentRuleWithResolvedDependencies, [
|
||||||
item.id,
|
item.id,
|
||||||
item.name,
|
item.name,
|
||||||
`visual.${item.id}`,
|
`visual.${item.id}`,
|
||||||
`visual.${item.name || item.id}`,
|
`visual.${item.name || item.id}`,
|
||||||
item.type,
|
item.type,
|
||||||
])),
|
])),
|
||||||
[currentRule, visualElements],
|
[currentRuleWithResolvedDependencies, visualElements],
|
||||||
);
|
);
|
||||||
const dialogDependencyOptions = useMemo(() => {
|
const dialogDependencyOptions = useMemo(() => {
|
||||||
const selectedValues = new Set(ruleDraft.dependencies);
|
const selectedValues = new Set(ruleDraft.dependencies);
|
||||||
@@ -644,7 +673,6 @@ export default function RulesTestDetail() {
|
|||||||
const fullYamlText = serializedYamlResult.yamlText;
|
const fullYamlText = serializedYamlResult.yamlText;
|
||||||
const isSmartRuleDraft = ruleDraft.type === 'ai_rule' || ruleDraft.checkTypes.includes('ai');
|
const isSmartRuleDraft = ruleDraft.type === 'ai_rule' || ruleDraft.checkTypes.includes('ai');
|
||||||
const isRuleGroupDraft = ruleDraft.type === 'rule_group';
|
const isRuleGroupDraft = ruleDraft.type === 'rule_group';
|
||||||
const rulesById = useMemo(() => new Map(rules.map(rule => [rule.ruleId || rule.id, rule])), [rules]);
|
|
||||||
const saveButtonBusy = saveFetcher.state !== 'idle';
|
const saveButtonBusy = saveFetcher.state !== 'idle';
|
||||||
const latestDraftVersion = useMemo(
|
const latestDraftVersion = useMemo(
|
||||||
() => versionItems.find((item) => !['published', 'rollback'].includes(item.status)),
|
() => versionItems.find((item) => !['published', 'rollback'].includes(item.status)),
|
||||||
@@ -1362,7 +1390,7 @@ export default function RulesTestDetail() {
|
|||||||
|
|
||||||
<Card
|
<Card
|
||||||
className="ant-card"
|
className="ant-card"
|
||||||
title={`依赖字段 (${currentRule.dependencies.length}项)`}
|
title={`依赖字段 (${resolvedCurrentDependencies.length}项)`}
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
className="rules-test-table"
|
className="rules-test-table"
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ function parseRules(source: string): RuleSummary[] {
|
|||||||
for (let index = start + 1; index < lines.length; index += 1) {
|
for (let index = start + 1; index < lines.length; index += 1) {
|
||||||
const line = lines[index];
|
const line = lines[index];
|
||||||
const lineIndent = line.match(/^\s*/)?.[0].length || 0;
|
const lineIndent = line.match(/^\s*/)?.[0].length || 0;
|
||||||
if (line.trim() && lineIndent <= baseIndent) {
|
if (line.trim() && lineIndent <= baseIndent && !/^\s*-\s+/.test(line)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const match = line.match(/^\s*-\s+(.+)$/);
|
const match = line.match(/^\s*-\s+(.+)$/);
|
||||||
@@ -313,7 +313,7 @@ function parseRules(source: string): RuleSummary[] {
|
|||||||
values.push(stripYamlValue(match[1]));
|
values.push(stripYamlValue(match[1]));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (line.trim() && lineIndent <= indent) break;
|
if (line.trim() && lineIndent <= indent && !/^\s*-\s+/.test(line)) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
@@ -331,7 +331,7 @@ function parseRules(source: string): RuleSummary[] {
|
|||||||
for (let index = start + 1; index < lines.length; index += 1) {
|
for (let index = start + 1; index < lines.length; index += 1) {
|
||||||
const line = lines[index];
|
const line = lines[index];
|
||||||
const lineIndent = line.match(/^\s*/)?.[0].length || 0;
|
const lineIndent = line.match(/^\s*/)?.[0].length || 0;
|
||||||
if (line.trim() && lineIndent <= baseIndent) {
|
if (line.trim() && lineIndent <= baseIndent && !/^\s*-\s+/.test(line)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const match = line.match(/^\s*-\s+(.+)$/);
|
const match = line.match(/^\s*-\s+(.+)$/);
|
||||||
@@ -342,6 +342,19 @@ function parseRules(source: string): RuleSummary[] {
|
|||||||
return values;
|
return values;
|
||||||
};
|
};
|
||||||
const readStageScalar = (block: string, key: string): string => stripYamlValue(block.match(new RegExp(`^\\s+${key}:\\s*(.+)$`, 'm'))?.[1] || '');
|
const readStageScalar = (block: string, key: string): string => stripYamlValue(block.match(new RegExp(`^\\s+${key}:\\s*(.+)$`, 'm'))?.[1] || '');
|
||||||
|
const readStagePairValues = (block: string): string[] => {
|
||||||
|
const lines = block.split('\n');
|
||||||
|
const values: string[] = [];
|
||||||
|
|
||||||
|
for (let index = 0; index < lines.length; index += 1) {
|
||||||
|
const match = lines[index].match(/^\s+(?:source|target|ref_field):\s*(.+)$/);
|
||||||
|
if (match) {
|
||||||
|
values.push(stripYamlValue(match[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
};
|
||||||
const summarizeStage = (stageBlock: string): string => {
|
const summarizeStage = (stageBlock: string): string => {
|
||||||
const fields = readStageList(stageBlock, 'fields');
|
const fields = readStageList(stageBlock, 'fields');
|
||||||
const field = readStageScalar(stageBlock, 'field');
|
const field = readStageScalar(stageBlock, 'field');
|
||||||
@@ -376,11 +389,22 @@ function parseRules(source: string): RuleSummary[] {
|
|||||||
const ruleId = stripYamlValue(ruleBlock.match(/^\s*-\s+rule_id:\s*(.+)$/m)?.[1] || '');
|
const ruleId = stripYamlValue(ruleBlock.match(/^\s*-\s+rule_id:\s*(.+)$/m)?.[1] || '');
|
||||||
const name = stripYamlValue(ruleBlock.match(/^\s+name:\s*(.+)$/m)?.[1] || '未命名规则');
|
const name = stripYamlValue(ruleBlock.match(/^\s+name:\s*(.+)$/m)?.[1] || '未命名规则');
|
||||||
const checkTypes = Array.from(new Set(Array.from(ruleBlock.matchAll(/^\s+(?:check|type):\s*(.+)$/gm)).map(match => stripYamlValue(match[1]))));
|
const checkTypes = Array.from(new Set(Array.from(ruleBlock.matchAll(/^\s+(?:check|type):\s*(.+)$/gm)).map(match => stripYamlValue(match[1]))));
|
||||||
const stageDependencies = Array.from(ruleBlock.matchAll(/^\s+(?:field|number|chinese|left|right|left_field|right_field|target|element|seal_id|signature_id):\s*(.+)$/gm))
|
const stageDependencies = Array.from(ruleBlock.matchAll(/^\s+(?:field|number|chinese|left|right|left_field|right_field|target|element|seal_id|signature_id|ref_field):\s*(.+)$/gm))
|
||||||
.map(match => normalizeDependency(match[1]));
|
.map(match => normalizeDependency(match[1]));
|
||||||
|
const stageFieldDependencies = splitBlocks(ruleBlock, /^\s{4,}-\s+id:\s*/)
|
||||||
|
.flatMap(stageBlock => [
|
||||||
|
...readStageList(stageBlock, 'fields'),
|
||||||
|
...readStagePairValues(stageBlock),
|
||||||
|
])
|
||||||
|
.map(normalizeDependency);
|
||||||
const prompts = readPrompts(ruleBlock);
|
const prompts = readPrompts(ruleBlock);
|
||||||
const promptDependencies = readPromptDependencies(prompts).map(normalizeDependency);
|
const promptDependencies = readPromptDependencies(prompts).map(normalizeDependency);
|
||||||
const dependencies = Array.from(new Set([...readExplicitDependencies(ruleBlock), ...stageDependencies, ...promptDependencies]));
|
const dependencies = Array.from(new Set([
|
||||||
|
...readExplicitDependencies(ruleBlock),
|
||||||
|
...stageDependencies,
|
||||||
|
...stageFieldDependencies,
|
||||||
|
...promptDependencies,
|
||||||
|
]));
|
||||||
const scope = Array.from(new Set(Array.from(ruleBlock.matchAll(/^\s{4,}-\s*([^:\n]+)$/gm)).map(match => stripYamlValue(match[1])).filter(value => !/^\d+$/.test(value))));
|
const scope = Array.from(new Set(Array.from(ruleBlock.matchAll(/^\s{4,}-\s*([^:\n]+)$/gm)).map(match => stripYamlValue(match[1])).filter(value => !/^\d+$/.test(value))));
|
||||||
const subRules = readSubRules(ruleBlock);
|
const subRules = readSubRules(ruleBlock);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user