mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-18 09:57:35 +02:00
Add files via upload
This commit is contained in:
+237
-15
@@ -15842,17 +15842,17 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
|||||||
|
|
||||||
.batch-queue-detail-kv {
|
.batch-queue-detail-kv {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
grid-template-columns: repeat(2, minmax(280px, 1fr));
|
||||||
gap: 10px 20px;
|
gap: 12px 32px;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bq-kv {
|
.bq-kv {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(100px, 34%) 1fr;
|
grid-template-columns: minmax(88px, 112px) 1fr;
|
||||||
gap: 8px 12px;
|
gap: 10px 16px;
|
||||||
align-items: start;
|
align-items: center;
|
||||||
padding: 8px 0;
|
padding: 10px 0;
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
@@ -15917,22 +15917,34 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
|||||||
|
|
||||||
/* Inline edit controls (replaces value in-place) */
|
/* Inline edit controls (replaces value in-place) */
|
||||||
.bq-inline-edit-controls {
|
.bq-inline-edit-controls {
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 10px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.bq-inline-edit-controls input[type="text"],
|
.bq-inline-edit-controls input[type="text"],
|
||||||
.bq-inline-edit-controls select {
|
.bq-inline-edit-controls select {
|
||||||
padding: 4px 8px;
|
padding: 8px 12px;
|
||||||
border-radius: 6px;
|
border-radius: 8px;
|
||||||
border: 1.5px solid var(--accent-color);
|
border: 1.5px solid var(--accent-color);
|
||||||
font-size: 13px;
|
font-size: 0.875rem;
|
||||||
outline: none;
|
outline: none;
|
||||||
background: var(--bg-primary);
|
background: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
transition: border-color 0.15s, box-shadow 0.15s;
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
}
|
}
|
||||||
|
.bq-inline-edit-controls input[type="text"] {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bq-inline-edit-controls .bq-edit-cron-expr {
|
||||||
|
flex: 1 1 280px;
|
||||||
|
min-width: 240px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
.bq-inline-edit-controls input[type="text"]:focus,
|
.bq-inline-edit-controls input[type="text"]:focus,
|
||||||
.bq-inline-edit-controls select:focus {
|
.bq-inline-edit-controls select:focus {
|
||||||
box-shadow: 0 0 0 2px rgba(0, 102, 255, 0.15);
|
box-shadow: 0 0 0 2px rgba(0, 102, 255, 0.15);
|
||||||
@@ -15960,11 +15972,18 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
|||||||
.batch-task-inline-edit textarea:focus {
|
.batch-task-inline-edit textarea:focus {
|
||||||
box-shadow: 0 0 0 2px rgba(0, 102, 255, 0.15);
|
box-shadow: 0 0 0 2px rgba(0, 102, 255, 0.15);
|
||||||
}
|
}
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.batch-queue-detail-kv {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 520px) {
|
@media (max-width: 520px) {
|
||||||
.bq-kv,
|
.bq-kv,
|
||||||
.bq-kv--block {
|
.bq-kv--block {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 4px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29318,7 +29337,8 @@ html[data-theme="dark"] .workflow-form-select-option:hover,
|
|||||||
html[data-theme="dark"] .projects-filter-select-option:hover,
|
html[data-theme="dark"] .projects-filter-select-option:hover,
|
||||||
html[data-theme="dark"] .chat-files-filter-select-option:hover,
|
html[data-theme="dark"] .chat-files-filter-select-option:hover,
|
||||||
html[data-theme="dark"] #role-modal .role-form-select-option:hover,
|
html[data-theme="dark"] #role-modal .role-form-select-option:hover,
|
||||||
html[data-theme="dark"] .monitor-filter-select-option:hover {
|
html[data-theme="dark"] .monitor-filter-select-option:hover,
|
||||||
|
html[data-theme="dark"] .batch-form-select-option:hover {
|
||||||
background: rgba(96, 165, 250, 0.12);
|
background: rgba(96, 165, 250, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29334,7 +29354,8 @@ html[data-theme="dark"] .workflow-form-select-option.is-selected,
|
|||||||
html[data-theme="dark"] .projects-filter-select-option.is-selected,
|
html[data-theme="dark"] .projects-filter-select-option.is-selected,
|
||||||
html[data-theme="dark"] .chat-files-filter-select-option.is-selected,
|
html[data-theme="dark"] .chat-files-filter-select-option.is-selected,
|
||||||
html[data-theme="dark"] #role-modal .role-form-select-option.is-selected,
|
html[data-theme="dark"] #role-modal .role-form-select-option.is-selected,
|
||||||
html[data-theme="dark"] .monitor-filter-select-option.is-selected {
|
html[data-theme="dark"] .monitor-filter-select-option.is-selected,
|
||||||
|
html[data-theme="dark"] .batch-form-select-option.is-selected {
|
||||||
background: rgba(96, 165, 250, 0.18);
|
background: rgba(96, 165, 250, 0.18);
|
||||||
color: var(--accent-hover);
|
color: var(--accent-hover);
|
||||||
}
|
}
|
||||||
@@ -29355,6 +29376,7 @@ html[data-theme="dark"] .workflow-tool-select-trigger,
|
|||||||
html[data-theme="dark"] .projects-filter-select-trigger,
|
html[data-theme="dark"] .projects-filter-select-trigger,
|
||||||
html[data-theme="dark"] .chat-files-filter-select-trigger,
|
html[data-theme="dark"] .chat-files-filter-select-trigger,
|
||||||
html[data-theme="dark"] .role-form-select-trigger,
|
html[data-theme="dark"] .role-form-select-trigger,
|
||||||
|
html[data-theme="dark"] .batch-form-select-trigger,
|
||||||
html[data-theme="dark"] .monitor-filter-select-trigger,
|
html[data-theme="dark"] .monitor-filter-select-trigger,
|
||||||
html[data-theme="dark"] .role-selector-btn,
|
html[data-theme="dark"] .role-selector-btn,
|
||||||
html[data-theme="dark"] .conversation-project-filter-trigger {
|
html[data-theme="dark"] .conversation-project-filter-trigger {
|
||||||
@@ -29383,6 +29405,7 @@ html[data-theme="dark"] .workflow-form-select-ui.open .workflow-form-select-trig
|
|||||||
html[data-theme="dark"] .projects-filter-select-ui.open .projects-filter-select-trigger,
|
html[data-theme="dark"] .projects-filter-select-ui.open .projects-filter-select-trigger,
|
||||||
html[data-theme="dark"] .chat-files-filter-select-ui.open .chat-files-filter-select-trigger,
|
html[data-theme="dark"] .chat-files-filter-select-ui.open .chat-files-filter-select-trigger,
|
||||||
html[data-theme="dark"] #role-modal .role-form-select-ui.open .role-form-select-trigger,
|
html[data-theme="dark"] #role-modal .role-form-select-ui.open .role-form-select-trigger,
|
||||||
|
html[data-theme="dark"] .batch-form-select-ui.open .batch-form-select-trigger,
|
||||||
html[data-theme="dark"] .monitor-filter-select-ui.open .monitor-filter-select-trigger {
|
html[data-theme="dark"] .monitor-filter-select-ui.open .monitor-filter-select-trigger {
|
||||||
border-color: var(--accent-color);
|
border-color: var(--accent-color);
|
||||||
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.16);
|
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.16);
|
||||||
@@ -31119,6 +31142,205 @@ html[data-theme="dark"] #agent-md-modal .modal-footer,
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 批量任务:新建队列 / 详情内联编辑 — 自定义下拉 */
|
||||||
|
.batch-form-native-select {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#batch-import-modal .batch-form-select-ui,
|
||||||
|
#batch-queue-detail-modal .batch-form-select-ui {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-ui--inline {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 220px;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-trigger {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 40px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.25;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: inherit;
|
||||||
|
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-ui--inline .batch-form-select-trigger {
|
||||||
|
min-height: 36px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
border-width: 1.5px;
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-trigger:hover:not(:disabled) {
|
||||||
|
border-color: rgba(59, 130, 246, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-ui.open .batch-form-select-trigger {
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-ui.open {
|
||||||
|
z-index: 120;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-ui.is-disabled .batch-form-select-trigger {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-value {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-caret {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
transition: transform 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-ui.open .batch-form-select-caret {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-dropdown {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 4px);
|
||||||
|
left: 0;
|
||||||
|
right: auto;
|
||||||
|
min-width: 100%;
|
||||||
|
width: max-content;
|
||||||
|
max-width: min(420px, calc(100vw - 48px));
|
||||||
|
z-index: 200;
|
||||||
|
max-height: 280px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 4px;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-ui.open .batch-form-select-dropdown {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-family: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
transition: background 0.12s ease, color 0.12s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-option:hover {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-option.is-selected {
|
||||||
|
background: rgba(59, 130, 246, 0.08);
|
||||||
|
color: #2563eb;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-check {
|
||||||
|
width: 14px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
color: #2563eb;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-option.is-selected .batch-form-select-check {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-label {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-ui--inline .batch-form-select-value {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-form-select-option .batch-form-select-label {
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: unset;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#batch-import-modal .modal-content:has(.batch-form-select-ui.open),
|
||||||
|
#batch-import-modal .modal-body:has(.batch-form-select-ui.open),
|
||||||
|
#batch-queue-detail-modal .modal-content:has(.batch-form-select-ui.open),
|
||||||
|
#batch-queue-detail-modal .modal-body:has(.batch-form-select-ui.open) {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bq-inline-edit-controls .batch-form-native-select {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bq-inline-edit-controls .batch-form-select-ui--inline {
|
||||||
|
margin: 0;
|
||||||
|
flex: 1 1 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#batch-queue-detail-modal .bq-kv__v:has(.bq-inline-edit-controls) {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
#batch-queue-detail-modal .batch-queue-detail-tech__sum {
|
||||||
|
white-space: normal;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
html[data-theme="dark"] #role-modal .modal-content,
|
html[data-theme="dark"] #role-modal .modal-content,
|
||||||
html[data-theme="dark"] #role-modal .modal-header,
|
html[data-theme="dark"] #role-modal .modal-header,
|
||||||
html[data-theme="dark"] #role-modal .modal-body,
|
html[data-theme="dark"] #role-modal .modal-body,
|
||||||
|
|||||||
+236
-28
@@ -765,6 +765,7 @@ function toggleTasksAutoRefresh(enabled) {
|
|||||||
// 初始化任务管理页面
|
// 初始化任务管理页面
|
||||||
function initTasksPage() {
|
function initTasksPage() {
|
||||||
initBatchQueuesFilterSelects();
|
initBatchQueuesFilterSelects();
|
||||||
|
initBatchFormSelects();
|
||||||
// 恢复自动刷新设置
|
// 恢复自动刷新设置
|
||||||
const autoRefreshCheckbox = document.getElementById('tasks-auto-refresh');
|
const autoRefreshCheckbox = document.getElementById('tasks-auto-refresh');
|
||||||
if (autoRefreshCheckbox) {
|
if (autoRefreshCheckbox) {
|
||||||
@@ -930,6 +931,7 @@ async function showBatchImportModal() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await refreshBatchProjectSelectOptions();
|
await refreshBatchProjectSelectOptions();
|
||||||
|
refreshBatchFormSelects();
|
||||||
|
|
||||||
openAppModal('batch-import-modal', { focusEl: input });
|
openAppModal('batch-import-modal', { focusEl: input });
|
||||||
}
|
}
|
||||||
@@ -1299,6 +1301,207 @@ function initBatchQueuesFilterSelects() {
|
|||||||
syncAllBatchQueuesFilterSelects();
|
syncAllBatchQueuesFilterSelects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BATCH_IMPORT_FORM_SELECT_IDS = [
|
||||||
|
'batch-queue-role',
|
||||||
|
'batch-queue-project-id',
|
||||||
|
'batch-queue-agent-mode',
|
||||||
|
'batch-queue-schedule-mode',
|
||||||
|
];
|
||||||
|
const batchFormSelectMap = {};
|
||||||
|
let batchFormSelectDocBound = false;
|
||||||
|
const BATCH_FORM_SELECT_CARET = '<svg class="batch-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 closeAllBatchFormSelects() {
|
||||||
|
Object.keys(batchFormSelectMap).forEach(function (id) {
|
||||||
|
const reg = batchFormSelectMap[id];
|
||||||
|
if (!reg || !reg.wrapper) return;
|
||||||
|
reg.wrapper.classList.remove('open');
|
||||||
|
if (reg.trigger) reg.trigger.setAttribute('aria-expanded', 'false');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncBatchFormSelect(selectId) {
|
||||||
|
const reg = batchFormSelectMap[selectId];
|
||||||
|
if (!reg) return;
|
||||||
|
const select = reg.select;
|
||||||
|
const dropdown = reg.dropdown;
|
||||||
|
const trigger = reg.trigger;
|
||||||
|
const valueSpan = trigger.querySelector('.batch-form-select-value');
|
||||||
|
|
||||||
|
dropdown.innerHTML = '';
|
||||||
|
Array.prototype.forEach.call(select.options, function (opt) {
|
||||||
|
const item = document.createElement('button');
|
||||||
|
item.type = 'button';
|
||||||
|
item.className = 'batch-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 = 'batch-form-select-check';
|
||||||
|
check.setAttribute('aria-hidden', 'true');
|
||||||
|
check.textContent = '✓';
|
||||||
|
const label = document.createElement('span');
|
||||||
|
label.className = 'batch-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 syncAllBatchImportFormSelects() {
|
||||||
|
BATCH_IMPORT_FORM_SELECT_IDS.forEach(syncBatchFormSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBatchFormSelectFocused(selectId) {
|
||||||
|
const active = document.activeElement;
|
||||||
|
if (!active) return false;
|
||||||
|
if (active.id === selectId) return true;
|
||||||
|
const reg = batchFormSelectMap[selectId];
|
||||||
|
return !!(reg && reg.wrapper && reg.wrapper.contains(active));
|
||||||
|
}
|
||||||
|
|
||||||
|
function focusBatchFormSelect(selectId) {
|
||||||
|
const reg = batchFormSelectMap[selectId];
|
||||||
|
if (reg && reg.trigger) {
|
||||||
|
reg.trigger.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const select = document.getElementById(selectId);
|
||||||
|
if (select) select.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindBatchInlineEditFocusOut(container, saveFn, isCancelledFn) {
|
||||||
|
if (!container) return;
|
||||||
|
container.addEventListener('focusout', function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
if (isCancelledFn && isCancelledFn()) return;
|
||||||
|
if (container.contains(document.activeElement)) return;
|
||||||
|
saveFn();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function enhanceBatchFormSelect(selectId, options) {
|
||||||
|
options = options || {};
|
||||||
|
const select = document.getElementById(selectId);
|
||||||
|
if (!select) return;
|
||||||
|
const existing = batchFormSelectMap[selectId];
|
||||||
|
if (existing && existing.select !== select) {
|
||||||
|
delete batchFormSelectMap[selectId];
|
||||||
|
}
|
||||||
|
if (select.dataset.batchFormCustom === '1') {
|
||||||
|
syncBatchFormSelect(selectId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
select.dataset.batchFormCustom = '1';
|
||||||
|
select.classList.add('batch-form-native-select');
|
||||||
|
select.tabIndex = -1;
|
||||||
|
select.setAttribute('aria-hidden', 'true');
|
||||||
|
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'batch-form-select-ui' + (options.inline ? ' batch-form-select-ui--inline' : '');
|
||||||
|
|
||||||
|
const trigger = document.createElement('button');
|
||||||
|
trigger.type = 'button';
|
||||||
|
trigger.className = 'batch-form-select-trigger';
|
||||||
|
trigger.setAttribute('aria-haspopup', 'listbox');
|
||||||
|
trigger.setAttribute('aria-expanded', 'false');
|
||||||
|
const valueSpan = document.createElement('span');
|
||||||
|
valueSpan.className = 'batch-form-select-value';
|
||||||
|
trigger.appendChild(valueSpan);
|
||||||
|
trigger.insertAdjacentHTML('beforeend', BATCH_FORM_SELECT_CARET);
|
||||||
|
|
||||||
|
const dropdown = document.createElement('div');
|
||||||
|
dropdown.className = 'batch-form-select-dropdown';
|
||||||
|
dropdown.setAttribute('role', 'listbox');
|
||||||
|
|
||||||
|
const parent = select.parentNode;
|
||||||
|
parent.insertBefore(wrapper, select);
|
||||||
|
wrapper.appendChild(trigger);
|
||||||
|
wrapper.appendChild(dropdown);
|
||||||
|
wrapper.appendChild(select);
|
||||||
|
|
||||||
|
batchFormSelectMap[selectId] = { 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');
|
||||||
|
closeAllBatchFormSelects();
|
||||||
|
if (!open) {
|
||||||
|
wrapper.classList.add('open');
|
||||||
|
trigger.setAttribute('aria-expanded', 'true');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dropdown.addEventListener('click', function (e) {
|
||||||
|
const opt = e.target.closest('.batch-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');
|
||||||
|
syncBatchFormSelect(selectId);
|
||||||
|
});
|
||||||
|
|
||||||
|
select.addEventListener('change', function () {
|
||||||
|
syncBatchFormSelect(selectId);
|
||||||
|
});
|
||||||
|
|
||||||
|
syncBatchFormSelect(selectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshBatchFormSelect(selectId, options) {
|
||||||
|
const select = document.getElementById(selectId);
|
||||||
|
if (!select) {
|
||||||
|
delete batchFormSelectMap[selectId];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
enhanceBatchFormSelect(selectId, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshBatchFormSelects() {
|
||||||
|
Object.keys(batchFormSelectMap).forEach(function (id) {
|
||||||
|
if (!document.getElementById(id)) delete batchFormSelectMap[id];
|
||||||
|
});
|
||||||
|
BATCH_IMPORT_FORM_SELECT_IDS.forEach(function (id) {
|
||||||
|
enhanceBatchFormSelect(id, { inline: false });
|
||||||
|
});
|
||||||
|
if (!batchFormSelectDocBound) {
|
||||||
|
batchFormSelectDocBound = true;
|
||||||
|
document.addEventListener('click', function (e) {
|
||||||
|
if (e.target.closest('.batch-form-select-ui')) return;
|
||||||
|
closeAllBatchFormSelects();
|
||||||
|
});
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Escape') closeAllBatchFormSelects();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
syncAllBatchImportFormSelects();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initBatchFormSelects() {
|
||||||
|
refreshBatchFormSelects();
|
||||||
|
}
|
||||||
|
|
||||||
// 筛选批量任务队列
|
// 筛选批量任务队列
|
||||||
function filterBatchQueues() {
|
function filterBatchQueues() {
|
||||||
const statusFilter = document.getElementById('batch-queues-status-filter');
|
const statusFilter = document.getElementById('batch-queues-status-filter');
|
||||||
@@ -2337,15 +2540,20 @@ function startInlineEditRole() {
|
|||||||
${orphanOpt}${opts}
|
${orphanOpt}${opts}
|
||||||
</select>
|
</select>
|
||||||
</span>`;
|
</span>`;
|
||||||
|
refreshBatchFormSelect('bq-edit-role', { inline: true });
|
||||||
const sel = document.getElementById('bq-edit-role');
|
const sel = document.getElementById('bq-edit-role');
|
||||||
|
const controls = container.querySelector('.bq-inline-edit-controls');
|
||||||
|
const roleReg = batchFormSelectMap['bq-edit-role'];
|
||||||
if (sel) {
|
if (sel) {
|
||||||
sel.focus();
|
focusBatchFormSelect('bq-edit-role');
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
sel.addEventListener('keydown', (e) => {
|
const onEscape = (e) => {
|
||||||
if (e.key === 'Escape') { cancelled = true; cancelAllInlineEdits(); }
|
if (e.key === 'Escape') { cancelled = true; cancelAllInlineEdits(); }
|
||||||
});
|
};
|
||||||
|
sel.addEventListener('keydown', onEscape);
|
||||||
|
if (roleReg && roleReg.trigger) roleReg.trigger.addEventListener('keydown', onEscape);
|
||||||
sel.addEventListener('change', () => { if (!cancelled) saveInlineRole(); });
|
sel.addEventListener('change', () => { if (!cancelled) saveInlineRole(); });
|
||||||
sel.addEventListener('blur', () => { if (!cancelled) saveInlineRole(); });
|
bindBatchInlineEditFocusOut(controls, () => { if (!cancelled) saveInlineRole(); }, () => cancelled);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2397,15 +2605,20 @@ function startInlineEditAgentMode() {
|
|||||||
<option value="supervisor" ${currentMode === 'supervisor' ? 'selected' : ''}>${escapeHtml(_t('chat.agentModeSupervisorLabel'))}</option>
|
<option value="supervisor" ${currentMode === 'supervisor' ? 'selected' : ''}>${escapeHtml(_t('chat.agentModeSupervisorLabel'))}</option>
|
||||||
</select>
|
</select>
|
||||||
</span>`;
|
</span>`;
|
||||||
|
refreshBatchFormSelect('bq-edit-agentmode', { inline: true });
|
||||||
const sel = document.getElementById('bq-edit-agentmode');
|
const sel = document.getElementById('bq-edit-agentmode');
|
||||||
|
const controls = container.querySelector('.bq-inline-edit-controls');
|
||||||
|
const modeReg = batchFormSelectMap['bq-edit-agentmode'];
|
||||||
if (sel) {
|
if (sel) {
|
||||||
sel.focus();
|
focusBatchFormSelect('bq-edit-agentmode');
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
sel.addEventListener('keydown', (e) => {
|
const onEscape = (e) => {
|
||||||
if (e.key === 'Escape') { cancelled = true; cancelAllInlineEdits(); }
|
if (e.key === 'Escape') { cancelled = true; cancelAllInlineEdits(); }
|
||||||
});
|
};
|
||||||
|
sel.addEventListener('keydown', onEscape);
|
||||||
|
if (modeReg && modeReg.trigger) modeReg.trigger.addEventListener('keydown', onEscape);
|
||||||
sel.addEventListener('change', () => { if (!cancelled) saveInlineAgentMode(); });
|
sel.addEventListener('change', () => { if (!cancelled) saveInlineAgentMode(); });
|
||||||
sel.addEventListener('blur', () => { if (!cancelled) saveInlineAgentMode(); });
|
bindBatchInlineEditFocusOut(controls, () => { if (!cancelled) saveInlineAgentMode(); }, () => cancelled);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2543,45 +2756,38 @@ function startInlineEditSchedule() {
|
|||||||
const queue = detail.queue;
|
const queue = detail.queue;
|
||||||
const isCron = queue.scheduleMode === 'cron';
|
const isCron = queue.scheduleMode === 'cron';
|
||||||
container.innerHTML = `<span class="bq-inline-edit-controls">
|
container.innerHTML = `<span class="bq-inline-edit-controls">
|
||||||
<select id="bq-edit-schedule-mode" onchange="toggleInlineScheduleCron()">
|
<select id="bq-edit-schedule-mode">
|
||||||
<option value="manual" ${!isCron ? 'selected' : ''}>${escapeHtml(_t('batchImportModal.scheduleModeManual'))}</option>
|
<option value="manual" ${!isCron ? 'selected' : ''}>${escapeHtml(_t('batchImportModal.scheduleModeManual'))}</option>
|
||||||
<option value="cron" ${isCron ? 'selected' : ''}>${escapeHtml(_t('batchImportModal.scheduleModeCron'))}</option>
|
<option value="cron" ${isCron ? 'selected' : ''}>${escapeHtml(_t('batchImportModal.scheduleModeCron'))}</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="text" id="bq-edit-cron-expr" value="${escapeHtml(queue.cronExpr || '')}" placeholder="${_t('batchImportModal.cronExprPlaceholder', { interpolation: { escapeValue: false } })}" style="width:200px;${!isCron ? 'display:none;' : ''}" />
|
<input type="text" id="bq-edit-cron-expr" class="bq-edit-cron-expr" value="${escapeHtml(queue.cronExpr || '')}" placeholder="${_t('batchImportModal.cronExprPlaceholder', { interpolation: { escapeValue: false } })}" style="${!isCron ? 'display:none;' : ''}" />
|
||||||
</span>`;
|
</span>`;
|
||||||
|
refreshBatchFormSelect('bq-edit-schedule-mode', { inline: true });
|
||||||
let schedCancelled = false;
|
let schedCancelled = false;
|
||||||
const sel = document.getElementById('bq-edit-schedule-mode');
|
const sel = document.getElementById('bq-edit-schedule-mode');
|
||||||
const cronInp = document.getElementById('bq-edit-cron-expr');
|
const cronInp = document.getElementById('bq-edit-cron-expr');
|
||||||
|
const controls = container.querySelector('.bq-inline-edit-controls');
|
||||||
|
const schedReg = batchFormSelectMap['bq-edit-schedule-mode'];
|
||||||
|
const onSchedEscape = (e) => { if (e.key === 'Escape') { schedCancelled = true; cancelAllInlineEdits(); } };
|
||||||
if (sel) {
|
if (sel) {
|
||||||
sel.focus();
|
focusBatchFormSelect('bq-edit-schedule-mode');
|
||||||
sel.addEventListener('keydown', (e) => { if (e.key === 'Escape') { schedCancelled = true; cancelAllInlineEdits(); } });
|
sel.addEventListener('keydown', onSchedEscape);
|
||||||
|
if (schedReg && schedReg.trigger) schedReg.trigger.addEventListener('keydown', onSchedEscape);
|
||||||
sel.addEventListener('change', () => {
|
sel.addEventListener('change', () => {
|
||||||
toggleInlineScheduleCron();
|
toggleInlineScheduleCron();
|
||||||
// 切到 manual 时直接保存;切到 cron 时等用户输入表达式后 blur 保存
|
|
||||||
if (sel.value !== 'cron' && !schedCancelled) saveInlineSchedule();
|
if (sel.value !== 'cron' && !schedCancelled) saveInlineSchedule();
|
||||||
});
|
});
|
||||||
sel.addEventListener('blur', (e) => {
|
|
||||||
// 如果焦点移到了 cron 输入框,不触发保存
|
|
||||||
setTimeout(() => {
|
|
||||||
const active = document.activeElement;
|
|
||||||
if (active && (active.id === 'bq-edit-cron-expr' || active.id === 'bq-edit-schedule-mode')) return;
|
|
||||||
if (!schedCancelled) saveInlineSchedule();
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (cronInp) {
|
if (cronInp) {
|
||||||
cronInp.addEventListener('keydown', (e) => {
|
cronInp.addEventListener('keydown', (e) => {
|
||||||
if (e.key === 'Enter') { e.preventDefault(); cronInp.blur(); }
|
if (e.key === 'Enter') { e.preventDefault(); cronInp.blur(); }
|
||||||
if (e.key === 'Escape') { schedCancelled = true; cancelAllInlineEdits(); }
|
if (e.key === 'Escape') { schedCancelled = true; cancelAllInlineEdits(); }
|
||||||
});
|
});
|
||||||
cronInp.addEventListener('blur', () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
const active = document.activeElement;
|
|
||||||
if (active && (active.id === 'bq-edit-cron-expr' || active.id === 'bq-edit-schedule-mode')) return;
|
|
||||||
if (!schedCancelled) saveInlineSchedule();
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
bindBatchInlineEditFocusOut(controls, () => {
|
||||||
|
if (schedCancelled) return;
|
||||||
|
saveInlineSchedule();
|
||||||
|
}, () => schedCancelled);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function toggleInlineScheduleCron() {
|
function toggleInlineScheduleCron() {
|
||||||
@@ -2675,6 +2881,7 @@ window.saveInlineSchedule = saveInlineSchedule;
|
|||||||
document.addEventListener('languagechange', function () {
|
document.addEventListener('languagechange', function () {
|
||||||
try {
|
try {
|
||||||
syncAllBatchQueuesFilterSelects();
|
syncAllBatchQueuesFilterSelects();
|
||||||
|
syncAllBatchImportFormSelects();
|
||||||
const tasksPage = document.getElementById('page-tasks');
|
const tasksPage = document.getElementById('page-tasks');
|
||||||
if (!tasksPage || !tasksPage.classList.contains('active')) {
|
if (!tasksPage || !tasksPage.classList.contains('active')) {
|
||||||
return;
|
return;
|
||||||
@@ -2697,4 +2904,5 @@ document.addEventListener('languagechange', function () {
|
|||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
initBatchQueuesFilterSelects();
|
initBatchQueuesFilterSelects();
|
||||||
|
initBatchFormSelects();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4753,21 +4753,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="batch-queue-role" data-i18n="batchImportModal.role">角色</label>
|
<label for="batch-queue-role" data-i18n="batchImportModal.role">角色</label>
|
||||||
<select id="batch-queue-role" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 0.875rem;">
|
<select id="batch-queue-role">
|
||||||
<option value="" data-i18n="batchImportModal.defaultRole">默认</option>
|
<option value="" data-i18n="batchImportModal.defaultRole">默认</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="form-hint" style="margin-top: 4px;" data-i18n="batchImportModal.roleHint">选择一个角色,所有任务将使用该角色的配置(提示词和工具)执行。</div>
|
<div class="form-hint" style="margin-top: 4px;" data-i18n="batchImportModal.roleHint">选择一个角色,所有任务将使用该角色的配置(提示词和工具)执行。</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="batch-queue-project-id" data-i18n="batchImportModal.project">所属项目</label>
|
<label for="batch-queue-project-id" data-i18n="batchImportModal.project">所属项目</label>
|
||||||
<select id="batch-queue-project-id" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 0.875rem;">
|
<select id="batch-queue-project-id">
|
||||||
<option value="" data-i18n="batchImportModal.projectNone">(未绑定)</option>
|
<option value="" data-i18n="batchImportModal.projectNone">(未绑定)</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="form-hint" style="margin-top: 4px;" data-i18n="batchImportModal.projectHint">可为队列绑定项目;留空则不绑定项目上下文。</div>
|
<div class="form-hint" style="margin-top: 4px;" data-i18n="batchImportModal.projectHint">可为队列绑定项目;留空则不绑定项目上下文。</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="batch-queue-agent-mode" data-i18n="batchImportModal.agentMode">代理模式</label>
|
<label for="batch-queue-agent-mode" data-i18n="batchImportModal.agentMode">代理模式</label>
|
||||||
<select id="batch-queue-agent-mode" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 0.875rem;">
|
<select id="batch-queue-agent-mode">
|
||||||
<option value="eino_single" data-i18n="chat.agentModeEinoSingle">Eino 单代理(ADK)</option>
|
<option value="eino_single" data-i18n="chat.agentModeEinoSingle">Eino 单代理(ADK)</option>
|
||||||
<option value="deep" data-i18n="chat.agentModeDeep">Deep(DeepAgent)</option>
|
<option value="deep" data-i18n="chat.agentModeDeep">Deep(DeepAgent)</option>
|
||||||
<option value="plan_execute" data-i18n="chat.agentModePlanExecuteLabel">Plan-Execute</option>
|
<option value="plan_execute" data-i18n="chat.agentModePlanExecuteLabel">Plan-Execute</option>
|
||||||
@@ -4782,7 +4782,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="batch-queue-schedule-mode" data-i18n="batchImportModal.scheduleMode">调度方式</label>
|
<label for="batch-queue-schedule-mode" data-i18n="batchImportModal.scheduleMode">调度方式</label>
|
||||||
<select id="batch-queue-schedule-mode" onchange="handleBatchScheduleModeChange()" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 0.875rem;">
|
<select id="batch-queue-schedule-mode" onchange="handleBatchScheduleModeChange()">
|
||||||
<option value="manual" data-i18n="batchImportModal.scheduleModeManual">手工执行</option>
|
<option value="manual" data-i18n="batchImportModal.scheduleModeManual">手工执行</option>
|
||||||
<option value="cron" data-i18n="batchImportModal.scheduleModeCron">调度表达式(Cron)</option>
|
<option value="cron" data-i18n="batchImportModal.scheduleModeCron">调度表达式(Cron)</option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
Reference in New Issue
Block a user