|
|
@@ -2269,9 +2269,9 @@ window.renderStructuredData = function(items, type, parentItem = null) {
|
|
|
|
|
|
// Tree node tags (from apply_to keys) or unstructured_what fallback
|
|
|
const getApplyToField = (it) => {
|
|
|
- if (it.apply_to_grounding) return { key: 'apply_to_grounding', val: it.apply_to_grounding };
|
|
|
- if (it.apply_to_draft) return { key: 'apply_to_draft', val: it.apply_to_draft };
|
|
|
- if (it.apply_to) return { key: 'apply_to', val: it.apply_to };
|
|
|
+ if (it.apply_to_grounding) return { key: 'apply_to_grounding', val: it.apply_to_grounding, suggest: it.suggest_apply_to };
|
|
|
+ if (it.apply_to_draft) return { key: 'apply_to_draft', val: it.apply_to_draft, suggest: null };
|
|
|
+ if (it.apply_to) return { key: 'apply_to', val: it.apply_to, suggest: it.suggest_apply_to };
|
|
|
return null;
|
|
|
};
|
|
|
const applyToData = getApplyToField(item);
|
|
|
@@ -2310,17 +2310,32 @@ window.renderStructuredData = function(items, type, parentItem = null) {
|
|
|
</div>
|
|
|
`;
|
|
|
|
|
|
- const renderApplyToVal = (valObj, isIdeal = false) => {
|
|
|
+ const renderApplyToVal = (valObj, suggestApplyTo = null) => {
|
|
|
if (!valObj || typeof valObj !== 'object') return '-';
|
|
|
+ const escapeApplyToText = (s) => String(s).replace(/</g, '<').replace(/>/g, '>');
|
|
|
+ const renderPathParts = (pathValue, highlight = false) => {
|
|
|
+ const pathStr = String(pathValue || '').trim();
|
|
|
+ if (!pathStr) return '';
|
|
|
+ const parts = pathStr.split('/');
|
|
|
+ const leaf = parts.pop();
|
|
|
+ const prefix = parts.length > 0 ? parts.join('/') + '/' : '';
|
|
|
+ const leafStyle = highlight
|
|
|
+ ? 'background:#eff6ff; color:#2563eb; border:1px solid #bfdbfe;'
|
|
|
+ : '';
|
|
|
+ return `
|
|
|
+ ${prefix ? `<span class="apply-to-path-prefix">${escapeApplyToText(prefix)}</span>` : ''}
|
|
|
+ <span class="apply-to-path-leaf" style="${leafStyle}">${escapeApplyToText(leaf)}</span>
|
|
|
+ `;
|
|
|
+ };
|
|
|
let res = '<div style="display:flex; flex-direction:column; gap:6px;">';
|
|
|
+ let hasRows = false;
|
|
|
Object.entries(valObj).forEach(([k, v]) => {
|
|
|
if (Array.isArray(v) && v.length > 0) {
|
|
|
+ hasRows = true;
|
|
|
res += `<div class="apply-to-subrow">
|
|
|
- <span class="apply-to-key-badge" style="background: rgba(0,0,0,0.05); color: #475569;">${k}</span>
|
|
|
+ <span class="apply-to-key-badge" style="background: rgba(0,0,0,0.05); color: #475569;">${escapeApplyToText(k)}</span>
|
|
|
<div class="apply-to-values" style="display:flex; flex-wrap:wrap; gap:4px;">`;
|
|
|
-
|
|
|
- let idealBadges = [];
|
|
|
-
|
|
|
+
|
|
|
v.forEach(pathObj => {
|
|
|
let pathStr = '';
|
|
|
let elementStr = '';
|
|
|
@@ -2336,87 +2351,46 @@ window.renderStructuredData = function(items, type, parentItem = null) {
|
|
|
tooltipHtml = `
|
|
|
<div class="apply-to-tooltip">
|
|
|
${pathObj.category_id ? `<span class="tooltip-id">id: ${pathObj.category_id}</span>` : ''}
|
|
|
- <span class="tooltip-rationale">${pathObj.rationale.replace(/</g, '<').replace(/>/g, '>')}</span>
|
|
|
+ <span class="tooltip-rationale">${escapeApplyToText(pathObj.rationale)}</span>
|
|
|
</div>
|
|
|
`;
|
|
|
}
|
|
|
|
|
|
let htmlParts = '';
|
|
|
if (pathStr && elementStr) {
|
|
|
- htmlParts = `<span class="apply-to-path-prefix">${pathStr}</span><span class="apply-to-path-leaf" style="margin-left: 4px;">${elementStr}</span>`;
|
|
|
+ htmlParts = `<span class="apply-to-path-prefix">${escapeApplyToText(pathStr)}</span><span class="apply-to-path-leaf" style="margin-left: 4px;">${escapeApplyToText(elementStr)}</span>`;
|
|
|
} else if (pathStr) {
|
|
|
- const parts = pathStr.split('/');
|
|
|
- const leaf = parts.pop();
|
|
|
- const prefix = parts.length > 0 ? parts.join('/') + '/' : '';
|
|
|
- htmlParts = `
|
|
|
- ${prefix ? `<span class="apply-to-path-prefix">${prefix}</span>` : ''}
|
|
|
- <span class="apply-to-path-leaf">${leaf}</span>
|
|
|
- `;
|
|
|
+ htmlParts = renderPathParts(pathStr);
|
|
|
}
|
|
|
|
|
|
if (htmlParts) {
|
|
|
res += `<span class="apply-to-path-item has-tooltip">${htmlParts}${tooltipHtml}</span>`;
|
|
|
}
|
|
|
-
|
|
|
- if (typeof pathObj === 'object' && pathObj !== null && pathObj.ideal_path) {
|
|
|
- let fullNormalPath = pathStr || '';
|
|
|
- if (elementStr) {
|
|
|
- if (!fullNormalPath.endsWith('/')) fullNormalPath += '/';
|
|
|
- fullNormalPath += elementStr;
|
|
|
- }
|
|
|
-
|
|
|
- if (fullNormalPath !== pathObj.ideal_path) {
|
|
|
- const normalParts = fullNormalPath.split('/');
|
|
|
- const idealParts = pathObj.ideal_path.split('/');
|
|
|
- const idealLeaf = idealParts.pop();
|
|
|
-
|
|
|
- let prefixHtml = '';
|
|
|
- if (idealParts.length > 0) {
|
|
|
- prefixHtml += `<span class="apply-to-path-prefix">`;
|
|
|
- for (let i = 0; i < idealParts.length; i++) {
|
|
|
- if (i === 0 && idealParts[0] === '') {
|
|
|
- prefixHtml += '/';
|
|
|
- continue;
|
|
|
- }
|
|
|
- const p = idealParts[i];
|
|
|
- const isNew = i >= normalParts.length || p !== normalParts[i];
|
|
|
- if (isNew) {
|
|
|
- prefixHtml += `<span style="color:#3b82f6; font-weight:600;">${p}</span>/`;
|
|
|
- } else {
|
|
|
- prefixHtml += `${p}/`;
|
|
|
- }
|
|
|
- }
|
|
|
- prefixHtml += `</span>`;
|
|
|
- }
|
|
|
-
|
|
|
- const isLeafNew = idealParts.length >= normalParts.length || idealLeaf !== normalParts[idealParts.length];
|
|
|
-
|
|
|
- const leafHtml = isLeafNew
|
|
|
- ? `<span class="apply-to-path-leaf" style="background:#eff6ff; color:#2563eb; border:1px solid #bfdbfe;">${idealLeaf}</span>`
|
|
|
- : `<span class="apply-to-path-leaf" style="background:#f1f5f9; color:#475569; border:1px solid #cbd5e1;">${idealLeaf}</span>`;
|
|
|
-
|
|
|
- const idealHtml = `${prefixHtml}${leafHtml}`;
|
|
|
- idealBadges.push(`<span class="apply-to-path-item has-tooltip" style="border: 2px dashed #94a3b8; background: transparent; margin-top: 4px;">${idealHtml}${tooltipHtml}</span>`);
|
|
|
- }
|
|
|
- }
|
|
|
});
|
|
|
-
|
|
|
- if (idealBadges.length > 0) {
|
|
|
- res += `<div style="flex-basis: 100%; height: 0; margin: 0;"></div>` + idealBadges.join('');
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
res += `</div></div>`;
|
|
|
}
|
|
|
});
|
|
|
+
|
|
|
+ if (typeof suggestApplyTo === 'string' && suggestApplyTo.trim()) {
|
|
|
+ hasRows = true;
|
|
|
+ res += `<div class="apply-to-subrow">
|
|
|
+ <span class="apply-to-key-badge" style="background:#eff6ff; color:#2563eb; border-color:#bfdbfe;">最优</span>
|
|
|
+ <div class="apply-to-values" style="display:flex; flex-wrap:wrap; gap:4px;">
|
|
|
+ <span class="apply-to-path-item" style="border: 2px dashed #94a3b8; background: transparent;">${renderPathParts(suggestApplyTo, true)}</span>
|
|
|
+ </div>
|
|
|
+ </div>`;
|
|
|
+ }
|
|
|
+
|
|
|
res += `</div>`;
|
|
|
- return res === '<div style="display:flex; flex-direction:column; gap:6px;"></div>' ? '-' : res;
|
|
|
+ return hasRows ? res : '-';
|
|
|
};
|
|
|
|
|
|
// Render apply_to / apply_to_grounding at workflow level (if it exists)
|
|
|
if (applyToData && typeof applyToData.val === 'object' && Object.keys(applyToData.val).length > 0) {
|
|
|
html += `<div class="structured-row">
|
|
|
<div class="structured-label">${applyToData.key}</div>
|
|
|
- <div class="structured-value">${renderApplyToVal(applyToData.val)}</div>
|
|
|
+ <div class="structured-value">${renderApplyToVal(applyToData.val, applyToData.suggest)}</div>
|
|
|
</div>`;
|
|
|
}
|
|
|
|
|
|
@@ -2653,6 +2627,7 @@ window.renderStructuredData = function(items, type, parentItem = null) {
|
|
|
const matchedFragments = new Set();
|
|
|
const renderFragmentColumns = (fragment) => {
|
|
|
const applyTo = fragment && (fragment.apply_to_draft || fragment.apply_to_grounding || fragment.apply_to);
|
|
|
+ const suggestApplyTo = fragment && fragment.apply_to_draft ? null : fragment && fragment.suggest_apply_to;
|
|
|
return `
|
|
|
<td class="fragment-cell" style="font-family: monospace;">
|
|
|
<span class="row-expand-icon">▶</span>
|
|
|
@@ -2662,7 +2637,7 @@ window.renderStructuredData = function(items, type, parentItem = null) {
|
|
|
<td class="fragment-cell">${fragment && fragment.inputs && fragment.inputs.length > 0 ? renderDataObjList(fragment.inputs) : '-'}</td>
|
|
|
<td class="fragment-cell">${fragment && fragment.outputs && fragment.outputs.length > 0 ? renderDataObjList(fragment.outputs) : '-'}</td>
|
|
|
<td class="fragment-cell"><div class="fragment-clamp">${fragment ? renderEffects(fragment.effects) : '-'}</div></td>
|
|
|
- <td class="fragment-cell" style="font-size:0.9em;"><div class="fragment-clamp">${applyTo ? renderApplyToVal(applyTo) : '-'}</div></td>
|
|
|
+ <td class="fragment-cell" style="font-size:0.9em;"><div class="fragment-clamp">${applyTo ? renderApplyToVal(applyTo, suggestApplyTo) : '-'}</div></td>
|
|
|
<td class="fragment-cell"><div class="fragment-clamp">${fragment ? renderTools(fragment.tools) : '-'}</div></td>
|
|
|
<td class="fragment-cell"><div class="fragment-clamp fragment-text">${fragment && fragment.body ? escapeHtml(fragment.body) : '-'}</div></td>
|
|
|
`;
|
|
|
@@ -2793,7 +2768,7 @@ window.renderStructuredData = function(items, type, parentItem = null) {
|
|
|
// Dynamic fallback for any other unhandled keys
|
|
|
const handledKeys = [
|
|
|
'method', 'name', 'action', 'unstructured_what', 'apply_to_grounding', 'apply_to_draft', 'apply_to',
|
|
|
- 'stage', 'effects', 'body', 'steps', 'inputs', 'outputs', 'tools'
|
|
|
+ 'suggest_apply_to', 'stage', 'effects', 'body', 'steps', 'inputs', 'outputs', 'tools'
|
|
|
];
|
|
|
|
|
|
Object.keys(item).forEach(k => {
|