mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-27 13:23:10 +02:00
Add files via upload
This commit is contained in:
+165
-5
@@ -90,7 +90,7 @@
|
||||
<div class="form-group">
|
||||
<label>${esc(label)}</label>
|
||||
<div class="workflow-binding-row" style="display:flex;gap:8px;">
|
||||
<select id="${prefix}-from" onchange="updateWorkflowTypedConfig()" style="flex:1;">${options}</select>
|
||||
<select id="${prefix}-from" class="workflow-form-select-native" onchange="updateWorkflowTypedConfig()" style="flex:1;">${options}</select>
|
||||
<input type="text" id="${prefix}-field" value="${esc(field)}" placeholder="output" oninput="updateWorkflowTypedConfig()" style="flex:1;">
|
||||
</div>
|
||||
${hint ? '<p class="workflow-config-hint">' + hint + '</p>' : ''}
|
||||
@@ -534,6 +534,7 @@
|
||||
if (select.disabled) return;
|
||||
const open = wrapper.classList.contains('open');
|
||||
closeWorkflowToolSelect();
|
||||
closeAllWorkflowFormSelects();
|
||||
if (!open) {
|
||||
wrapper.classList.add('open');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
@@ -573,6 +574,160 @@
|
||||
syncWorkflowToolSelect();
|
||||
}
|
||||
|
||||
const workflowFormSelectMap = {};
|
||||
let workflowFormSelectDocBound = false;
|
||||
const WORKFLOW_FORM_SELECT_CARET = '<svg class="workflow-form-select-caret" width="14" height="14" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
||||
|
||||
function closeAllWorkflowFormSelects() {
|
||||
Object.keys(workflowFormSelectMap).forEach(function (id) {
|
||||
const reg = workflowFormSelectMap[id];
|
||||
if (!reg || !reg.wrapper) return;
|
||||
reg.wrapper.classList.remove('open');
|
||||
if (reg.trigger) reg.trigger.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
|
||||
function pruneWorkflowFormSelectMap(root) {
|
||||
Object.keys(workflowFormSelectMap).forEach(function (id) {
|
||||
const select = document.getElementById(id);
|
||||
if (!select || (root && !root.contains(select))) {
|
||||
delete workflowFormSelectMap[id];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function syncWorkflowFormSelect(select) {
|
||||
const reg = workflowFormSelectMap[select.id];
|
||||
if (!reg) return;
|
||||
const dropdown = reg.dropdown;
|
||||
const trigger = reg.trigger;
|
||||
const valueSpan = trigger.querySelector('.workflow-form-select-value');
|
||||
|
||||
dropdown.innerHTML = '';
|
||||
Array.prototype.forEach.call(select.options, function (opt) {
|
||||
const item = document.createElement('button');
|
||||
item.type = 'button';
|
||||
item.className = 'workflow-form-select-option';
|
||||
item.setAttribute('role', 'option');
|
||||
item.setAttribute('data-value', opt.value);
|
||||
if (opt.value === select.value) {
|
||||
item.classList.add('is-selected');
|
||||
item.setAttribute('aria-selected', 'true');
|
||||
} else {
|
||||
item.setAttribute('aria-selected', 'false');
|
||||
}
|
||||
const check = document.createElement('span');
|
||||
check.className = 'workflow-form-select-check';
|
||||
check.setAttribute('aria-hidden', 'true');
|
||||
check.textContent = '✓';
|
||||
const label = document.createElement('span');
|
||||
label.className = 'workflow-form-select-label';
|
||||
label.textContent = opt.textContent;
|
||||
item.appendChild(check);
|
||||
item.appendChild(label);
|
||||
dropdown.appendChild(item);
|
||||
});
|
||||
|
||||
const selectedOpt = select.options[select.selectedIndex];
|
||||
if (valueSpan) {
|
||||
valueSpan.textContent = selectedOpt ? selectedOpt.textContent : '';
|
||||
}
|
||||
trigger.disabled = !!select.disabled;
|
||||
reg.wrapper.classList.toggle('is-disabled', !!select.disabled);
|
||||
}
|
||||
|
||||
function enhanceWorkflowFormSelect(select) {
|
||||
if (!select || !select.id) return;
|
||||
if (select.id === WORKFLOW_TOOL_SELECT_ID) return;
|
||||
const existing = workflowFormSelectMap[select.id];
|
||||
if (existing && existing.select !== select) {
|
||||
delete workflowFormSelectMap[select.id];
|
||||
}
|
||||
if (select.dataset.workflowFormCustom === '1') {
|
||||
syncWorkflowFormSelect(select);
|
||||
return;
|
||||
}
|
||||
select.dataset.workflowFormCustom = '1';
|
||||
select.classList.add('workflow-form-native-select');
|
||||
select.tabIndex = -1;
|
||||
select.setAttribute('aria-hidden', 'true');
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'workflow-form-select-ui';
|
||||
|
||||
const trigger = document.createElement('button');
|
||||
trigger.type = 'button';
|
||||
trigger.className = 'workflow-form-select-trigger';
|
||||
trigger.setAttribute('aria-haspopup', 'listbox');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
const valueSpan = document.createElement('span');
|
||||
valueSpan.className = 'workflow-form-select-value';
|
||||
trigger.appendChild(valueSpan);
|
||||
trigger.insertAdjacentHTML('beforeend', WORKFLOW_FORM_SELECT_CARET);
|
||||
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.className = 'workflow-form-select-dropdown';
|
||||
dropdown.setAttribute('role', 'listbox');
|
||||
|
||||
const parent = select.parentNode;
|
||||
parent.insertBefore(wrapper, select);
|
||||
wrapper.appendChild(trigger);
|
||||
wrapper.appendChild(dropdown);
|
||||
wrapper.appendChild(select);
|
||||
|
||||
workflowFormSelectMap[select.id] = { wrapper: wrapper, trigger: trigger, dropdown: dropdown, select: select };
|
||||
|
||||
trigger.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
if (select.disabled) return;
|
||||
const open = wrapper.classList.contains('open');
|
||||
closeAllWorkflowFormSelects();
|
||||
closeWorkflowToolSelect();
|
||||
if (!open) {
|
||||
wrapper.classList.add('open');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click', function (e) {
|
||||
const opt = e.target.closest('.workflow-form-select-option');
|
||||
if (!opt) return;
|
||||
e.stopPropagation();
|
||||
const val = opt.getAttribute('data-value');
|
||||
if (val === null) return;
|
||||
if (select.value !== val) {
|
||||
select.value = val;
|
||||
select.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
wrapper.classList.remove('open');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
syncWorkflowFormSelect(select);
|
||||
});
|
||||
|
||||
select.addEventListener('change', function () {
|
||||
syncWorkflowFormSelect(select);
|
||||
});
|
||||
|
||||
syncWorkflowFormSelect(select);
|
||||
}
|
||||
|
||||
function refreshWorkflowPropertySelects() {
|
||||
const form = document.getElementById('workflow-property-form');
|
||||
if (!form || form.hidden) return;
|
||||
pruneWorkflowFormSelectMap(form);
|
||||
form.querySelectorAll('select').forEach(function (select) {
|
||||
if (select.id === WORKFLOW_TOOL_SELECT_ID) return;
|
||||
enhanceWorkflowFormSelect(select);
|
||||
});
|
||||
if (!workflowFormSelectDocBound) {
|
||||
workflowFormSelectDocBound = true;
|
||||
document.addEventListener('click', closeAllWorkflowFormSelects);
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') closeAllWorkflowFormSelects();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function readWorkflowMetaFromForm() {
|
||||
const idEl = document.getElementById('workflow-id');
|
||||
const nameEl = document.getElementById('workflow-name');
|
||||
@@ -794,7 +949,7 @@
|
||||
return `
|
||||
<div class="form-group">
|
||||
<label for="workflow-join-strategy">${esc(_t('workflows.config.joinStrategy') || '汇聚策略')}</label>
|
||||
<select id="workflow-join-strategy" onchange="updateWorkflowTypedConfig()">
|
||||
<select id="workflow-join-strategy" class="workflow-form-select-native" onchange="updateWorkflowTypedConfig()">
|
||||
${JOIN_STRATEGIES.map(strategy => `<option value="${strategy}" ${strategy === selected ? 'selected' : ''}>${strategy}</option>`).join('')}
|
||||
</select>
|
||||
<p class="workflow-config-hint">${esc(_t('workflows.config.joinStrategyHint') || '多个上游进入同一节点时如何生成 previous。')}</p>
|
||||
@@ -838,7 +993,7 @@
|
||||
${sourceType === 'condition' ? `
|
||||
<div class="form-group">
|
||||
<label for="workflow-edge-branch">${esc(_t('workflows.config.edgeBranch') || '条件分支')}</label>
|
||||
<select id="workflow-edge-branch" onchange="updateWorkflowTypedConfig()">
|
||||
<select id="workflow-edge-branch" class="workflow-form-select-native" onchange="updateWorkflowTypedConfig()">
|
||||
<option value="">${esc(_t('workflows.config.selectBranch') || '请选择')}</option>
|
||||
<option value="true" ${cfg.branch === 'true' ? 'selected' : ''}>true / 是</option>
|
||||
<option value="false" ${cfg.branch === 'false' ? 'selected' : ''}>false / 否</option>
|
||||
@@ -847,6 +1002,7 @@
|
||||
<p class="workflow-config-hint">${esc(_t('workflows.config.edgeBranchHint'))}</p>
|
||||
` : ''}
|
||||
`;
|
||||
refreshWorkflowPropertySelects();
|
||||
return;
|
||||
}
|
||||
const type = ele.data('type') || 'tool';
|
||||
@@ -879,7 +1035,7 @@
|
||||
${joinStrategyHtml(cfg)}
|
||||
<div class="form-group">
|
||||
<label for="workflow-agent-mode">${esc(_t('workflows.config.agentMode'))}</label>
|
||||
<select id="workflow-agent-mode" onchange="updateWorkflowTypedConfig()">
|
||||
<select id="workflow-agent-mode" class="workflow-form-select-native" onchange="updateWorkflowTypedConfig()">
|
||||
${AGENT_MODES.map(mode => `<option value="${mode}" ${mode === cfg.agent_mode ? 'selected' : ''}>${mode}</option>`).join('')}
|
||||
</select>
|
||||
</div>
|
||||
@@ -904,7 +1060,7 @@
|
||||
<p class="workflow-config-hint">${_t('workflows.config.hitlInteractiveHint')}</p>
|
||||
<div class="form-group">
|
||||
<label for="workflow-hitl-reviewer">${esc(_t('workflows.config.hitlReviewer'))}</label>
|
||||
<select id="workflow-hitl-reviewer" onchange="updateWorkflowTypedConfig()">
|
||||
<select id="workflow-hitl-reviewer" class="workflow-form-select-native" onchange="updateWorkflowTypedConfig()">
|
||||
<option value="human" ${cfg.reviewer === 'human' ? 'selected' : ''}>human</option>
|
||||
<option value="audit_agent" ${cfg.reviewer === 'audit_agent' ? 'selected' : ''}>audit_agent</option>
|
||||
</select>
|
||||
@@ -925,6 +1081,7 @@
|
||||
default:
|
||||
wrap.innerHTML = '';
|
||||
}
|
||||
refreshWorkflowPropertySelects();
|
||||
}
|
||||
|
||||
function renderCustomFields(config) {
|
||||
@@ -1688,6 +1845,9 @@
|
||||
`<option value="${esc(wf.id)}">${esc(wf.name || wf.id)}${wf.enabled ? '' : esc(_t('roleModal.workflowDisabledSuffix'))}</option>`
|
||||
)).join('');
|
||||
select.value = current || '';
|
||||
if (typeof window.refreshRoleModalSelects === 'function') {
|
||||
window.refreshRoleModalSelects();
|
||||
}
|
||||
};
|
||||
|
||||
function refreshCanvasLabels() {
|
||||
|
||||
Reference in New Issue
Block a user