mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-10 06:18:37 +02:00
Add files via upload
This commit is contained in:
@@ -179,6 +179,156 @@ html[data-theme="dark"] .c2-session-main-empty__icon {
|
||||
padding-right: 14px;
|
||||
}
|
||||
|
||||
.c2-modal select.form-control.c2-native-select {
|
||||
appearance: auto;
|
||||
-webkit-appearance: menulist-button;
|
||||
background-image: none;
|
||||
padding-right: 14px;
|
||||
}
|
||||
|
||||
.c2-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;
|
||||
}
|
||||
|
||||
.c2-form-select-ui {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.c2-form-select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
min-height: 40px;
|
||||
padding: 10px 14px;
|
||||
border: 1px solid var(--c2-border);
|
||||
border-radius: var(--c2-radius-sm);
|
||||
background: var(--c2-surface);
|
||||
color: var(--c2-text);
|
||||
font-size: 14px;
|
||||
line-height: 1.25;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.c2-form-select-trigger:hover:not(:disabled) {
|
||||
border-color: var(--c2-accent);
|
||||
}
|
||||
|
||||
.c2-form-select-ui.open .c2-form-select-trigger {
|
||||
border-color: var(--c2-accent);
|
||||
box-shadow: 0 0 0 2px var(--c2-accent-dim);
|
||||
}
|
||||
|
||||
.c2-form-select-ui.open {
|
||||
z-index: 120;
|
||||
}
|
||||
|
||||
.c2-form-select-ui.is-disabled .c2-form-select-trigger {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.c2-form-select-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.c2-form-select-caret {
|
||||
flex-shrink: 0;
|
||||
color: var(--c2-text-muted);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.c2-form-select-ui.open .c2-form-select-caret {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.c2-form-select-dropdown {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 200;
|
||||
max-height: 280px;
|
||||
overflow-y: auto;
|
||||
padding: 4px;
|
||||
background: var(--c2-surface);
|
||||
border: 1px solid var(--c2-border);
|
||||
border-radius: var(--c2-radius-sm);
|
||||
box-shadow: var(--c2-shadow-lg);
|
||||
}
|
||||
|
||||
.c2-form-select-ui.open .c2-form-select-dropdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.c2-form-select-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
padding: 8px 10px;
|
||||
border: none;
|
||||
border-radius: var(--c2-radius-xs);
|
||||
background: transparent;
|
||||
color: var(--c2-text);
|
||||
font-size: 13px;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition: background 0.12s ease, color 0.12s ease;
|
||||
}
|
||||
|
||||
.c2-form-select-option:hover {
|
||||
background: var(--c2-surface-alt);
|
||||
}
|
||||
|
||||
.c2-form-select-option.is-selected {
|
||||
background: var(--c2-accent-dim);
|
||||
color: var(--c2-accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.c2-form-select-check {
|
||||
width: 14px;
|
||||
flex-shrink: 0;
|
||||
visibility: hidden;
|
||||
color: var(--c2-accent);
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.c2-form-select-option.is-selected .c2-form-select-check {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.c2-form-select-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#page-c2-payloads textarea.form-control,
|
||||
.c2-modal textarea.form-control {
|
||||
resize: vertical;
|
||||
|
||||
+917
-3
@@ -2009,6 +2009,155 @@ html[data-theme="dark"] .openapi-doc-btn:hover {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.hitl-filter-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;
|
||||
}
|
||||
|
||||
.hitl-filters--logs .hitl-filter-select-ui {
|
||||
position: relative;
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.hitl-filters--logs .hitl-filter-select-ui--decision {
|
||||
min-width: 132px;
|
||||
}
|
||||
|
||||
.hitl-filters--logs .hitl-filter-select-ui--decidedby {
|
||||
min-width: 168px;
|
||||
}
|
||||
|
||||
.hitl-filter-select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--border-color, #e2e8f0);
|
||||
border-radius: 8px;
|
||||
background: var(--bg-primary, #fff);
|
||||
color: var(--text-primary, #0f172a);
|
||||
font-size: 13px;
|
||||
line-height: 1.25;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.hitl-filter-select-trigger:hover:not(:disabled) {
|
||||
border-color: rgba(59, 130, 246, 0.45);
|
||||
}
|
||||
|
||||
.hitl-filter-select-ui.open .hitl-filter-select-trigger {
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12);
|
||||
}
|
||||
|
||||
.hitl-filter-select-ui.open {
|
||||
z-index: 120;
|
||||
}
|
||||
|
||||
.hitl-filter-select-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.hitl-filter-select-caret {
|
||||
flex-shrink: 0;
|
||||
color: var(--text-secondary, #64748b);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.hitl-filter-select-ui.open .hitl-filter-select-caret {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.hitl-filter-select-dropdown {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 200;
|
||||
max-height: 280px;
|
||||
overflow-y: auto;
|
||||
padding: 4px;
|
||||
background: var(--bg-primary, #fff);
|
||||
border: 1px solid var(--border-color, #e2e8f0);
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
.hitl-filter-select-ui.open .hitl-filter-select-dropdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hitl-filter-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, #0f172a);
|
||||
font-size: 13px;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition: background 0.12s ease, color 0.12s ease;
|
||||
}
|
||||
|
||||
.hitl-filter-select-option:hover {
|
||||
background: var(--bg-secondary, #f8fafc);
|
||||
}
|
||||
|
||||
.hitl-filter-select-option.is-selected {
|
||||
background: rgba(59, 130, 246, 0.08);
|
||||
color: #2563eb;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.hitl-filter-select-check {
|
||||
width: 14px;
|
||||
flex-shrink: 0;
|
||||
visibility: hidden;
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.hitl-filter-select-option.is-selected .hitl-filter-select-check {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.hitl-filter-select-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.hitl-filter-select-ui.is-disabled .hitl-filter-select-trigger {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.hitl-logs-table-wrap {
|
||||
overflow-x: auto;
|
||||
border: 1px solid #e2e8f0;
|
||||
@@ -14618,6 +14767,147 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.tasks-filter-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-queues-filters.tasks-filters.batch-queues-filters--compact .tasks-filter-select-ui {
|
||||
position: relative;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.tasks-filter-select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.25;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.tasks-filter-select-trigger:hover:not(:disabled) {
|
||||
border-color: var(--accent-color);
|
||||
}
|
||||
|
||||
.tasks-filter-select-ui.open .tasks-filter-select-trigger {
|
||||
border-color: var(--accent-color);
|
||||
box-shadow: 0 0 0 2px rgba(0, 102, 255, 0.1);
|
||||
}
|
||||
|
||||
.tasks-filter-select-ui.open {
|
||||
z-index: 120;
|
||||
}
|
||||
|
||||
.tasks-filter-select-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tasks-filter-select-caret {
|
||||
flex-shrink: 0;
|
||||
color: var(--text-secondary);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.tasks-filter-select-ui.open .tasks-filter-select-caret {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.tasks-filter-select-dropdown {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
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);
|
||||
}
|
||||
|
||||
.tasks-filter-select-ui.open .tasks-filter-select-dropdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tasks-filter-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;
|
||||
}
|
||||
|
||||
.tasks-filter-select-option:hover {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.tasks-filter-select-option.is-selected {
|
||||
background: rgba(59, 130, 246, 0.08);
|
||||
color: #2563eb;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tasks-filter-select-check {
|
||||
width: 14px;
|
||||
flex-shrink: 0;
|
||||
visibility: hidden;
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tasks-filter-select-option.is-selected .tasks-filter-select-check {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.tasks-filter-select-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tasks-filter-select-ui.is-disabled .tasks-filter-select-trigger {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.batch-queues-filters.tasks-filters.batch-queues-filters--compact input[type="text"] {
|
||||
padding: 6px 10px;
|
||||
font-size: 0.8125rem;
|
||||
@@ -24832,6 +25122,147 @@ html[data-theme="dark"] .vulnerability-card:hover {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.chat-files-filter-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;
|
||||
}
|
||||
|
||||
.chat-files-filters .chat-files-filter-select-ui {
|
||||
position: relative;
|
||||
min-width: 168px;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
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;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-trigger:hover:not(:disabled) {
|
||||
border-color: var(--accent-color);
|
||||
}
|
||||
|
||||
.chat-files-filter-select-ui.open .chat-files-filter-select-trigger {
|
||||
border-color: var(--accent-color);
|
||||
box-shadow: 0 0 0 2px rgba(0, 102, 255, 0.1);
|
||||
}
|
||||
|
||||
.chat-files-filter-select-ui.open {
|
||||
z-index: 120;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-ui.is-disabled .chat-files-filter-select-trigger {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-caret {
|
||||
flex-shrink: 0;
|
||||
color: var(--text-secondary);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-ui.open .chat-files-filter-select-caret {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.chat-files-filter-select-dropdown {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
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);
|
||||
}
|
||||
|
||||
.chat-files-filter-select-ui.open .chat-files-filter-select-dropdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chat-files-filter-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;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-option:hover {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.chat-files-filter-select-option.is-selected {
|
||||
background: rgba(59, 130, 246, 0.08);
|
||||
color: #2563eb;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-check {
|
||||
width: 14px;
|
||||
flex-shrink: 0;
|
||||
visibility: hidden;
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-option.is-selected .chat-files-filter-select-check {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.chat-files-filter-select-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.chat-files-table-wrap {
|
||||
overflow-x: auto;
|
||||
background: var(--bg-primary);
|
||||
@@ -26684,6 +27115,175 @@ html[data-theme="dark"] .chat-files-toast.chat-toast--error {
|
||||
border-radius: 8px;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
|
||||
}
|
||||
|
||||
.projects-filter-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;
|
||||
}
|
||||
|
||||
.projects-fact-filter-field .projects-filter-select-ui {
|
||||
width: 100%;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.projects-filter-select-ui {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.projects-filter-select-ui--compact {
|
||||
display: inline-flex;
|
||||
min-width: 64px;
|
||||
}
|
||||
|
||||
.projects-filter-select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 34px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid var(--border-color, #e2e8f0);
|
||||
border-radius: 8px;
|
||||
background: var(--bg-primary, #f8fafc);
|
||||
color: var(--text-primary, #0f172a);
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.25;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
|
||||
}
|
||||
|
||||
.projects-settings-card .projects-filter-select-trigger {
|
||||
height: 38px;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.projects-filter-select-trigger:hover:not(:disabled) {
|
||||
border-color: rgba(59, 130, 246, 0.45);
|
||||
}
|
||||
|
||||
.projects-filter-select-ui.open .projects-filter-select-trigger {
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12);
|
||||
}
|
||||
|
||||
.projects-filter-select-ui.open {
|
||||
z-index: 120;
|
||||
}
|
||||
|
||||
.projects-filter-select-ui.is-disabled .projects-filter-select-trigger {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.projects-filter-select-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.projects-filter-select-caret {
|
||||
flex-shrink: 0;
|
||||
color: var(--text-secondary, #94a3b8);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.projects-filter-select-ui.open .projects-filter-select-caret {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.projects-filter-select-dropdown {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 200;
|
||||
max-height: 280px;
|
||||
overflow-y: auto;
|
||||
padding: 4px;
|
||||
background: var(--bg-primary, #fff);
|
||||
border: 1px solid var(--border-color, #e2e8f0);
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
.projects-filter-select-ui.open .projects-filter-select-dropdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.projects-filter-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, #0f172a);
|
||||
font-size: 0.8125rem;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition: background 0.12s ease, color 0.12s ease;
|
||||
}
|
||||
|
||||
.projects-filter-select-option:hover {
|
||||
background: var(--bg-secondary, #f1f5f9);
|
||||
}
|
||||
|
||||
.projects-filter-select-option.is-selected {
|
||||
background: rgba(59, 130, 246, 0.08);
|
||||
color: #2563eb;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.projects-filter-select-check {
|
||||
width: 14px;
|
||||
flex-shrink: 0;
|
||||
visibility: hidden;
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.projects-filter-select-option.is-selected .projects-filter-select-check {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.projects-filter-select-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sidebar-list-pagination .pagination-page-size .projects-filter-select-ui--compact {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.sidebar-list-pagination .pagination-page-size .projects-filter-select-trigger {
|
||||
height: 28px;
|
||||
padding: 0 8px;
|
||||
font-size: 0.75rem;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.projects-fact-filter-field--search input {
|
||||
padding-left: 34px;
|
||||
background: #fff;
|
||||
@@ -28556,7 +29156,13 @@ html[data-theme="dark"] .role-selection-item-main:hover,
|
||||
html[data-theme="dark"] .role-select-item:hover,
|
||||
html[data-theme="dark"] .custom-select-option:hover,
|
||||
html[data-theme="dark"] .audit-custom-select-option:hover,
|
||||
html[data-theme="dark"] .vuln-filter-select-option:hover {
|
||||
html[data-theme="dark"] .vuln-filter-select-option:hover,
|
||||
html[data-theme="dark"] .hitl-filter-select-option:hover,
|
||||
html[data-theme="dark"] .tasks-filter-select-option:hover,
|
||||
html[data-theme="dark"] .workflow-form-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"] #role-modal .role-form-select-option:hover {
|
||||
background: rgba(96, 165, 250, 0.12);
|
||||
}
|
||||
|
||||
@@ -28565,7 +29171,13 @@ html[data-theme="dark"] .role-selection-item-main.selected,
|
||||
html[data-theme="dark"] .role-select-item.selected,
|
||||
html[data-theme="dark"] .custom-select-option.selected,
|
||||
html[data-theme="dark"] .audit-custom-select-option.is-selected,
|
||||
html[data-theme="dark"] .vuln-filter-select-option.is-selected {
|
||||
html[data-theme="dark"] .vuln-filter-select-option.is-selected,
|
||||
html[data-theme="dark"] .hitl-filter-select-option.is-selected,
|
||||
html[data-theme="dark"] .tasks-filter-select-option.is-selected,
|
||||
html[data-theme="dark"] .workflow-form-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"] #role-modal .role-form-select-option.is-selected {
|
||||
background: rgba(96, 165, 250, 0.18);
|
||||
color: var(--accent-hover);
|
||||
}
|
||||
@@ -28579,6 +29191,13 @@ html[data-theme="dark"] .model-pick-input,
|
||||
html[data-theme="dark"] .custom-select-trigger,
|
||||
html[data-theme="dark"] .audit-custom-select-trigger,
|
||||
html[data-theme="dark"] .vuln-filter-select-trigger,
|
||||
html[data-theme="dark"] .hitl-filter-select-trigger,
|
||||
html[data-theme="dark"] .tasks-filter-select-trigger,
|
||||
html[data-theme="dark"] .workflow-form-select-trigger,
|
||||
html[data-theme="dark"] .workflow-tool-select-trigger,
|
||||
html[data-theme="dark"] .projects-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-selector-btn,
|
||||
html[data-theme="dark"] .conversation-project-filter-trigger {
|
||||
background: #0f172a;
|
||||
@@ -28599,7 +29218,13 @@ html[data-theme="dark"] .form-control:focus,
|
||||
html[data-theme="dark"] .model-pick-input:focus,
|
||||
html[data-theme="dark"] .custom-select.open .custom-select-trigger,
|
||||
html[data-theme="dark"] .audit-custom-select.open .audit-custom-select-trigger,
|
||||
html[data-theme="dark"] .vuln-filter-select.open .vuln-filter-select-trigger {
|
||||
html[data-theme="dark"] .vuln-filter-select.open .vuln-filter-select-trigger,
|
||||
html[data-theme="dark"] .hitl-filter-select-ui.open .hitl-filter-select-trigger,
|
||||
html[data-theme="dark"] .tasks-filter-select-ui.open .tasks-filter-select-trigger,
|
||||
html[data-theme="dark"] .workflow-form-select-ui.open .workflow-form-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"] #role-modal .role-form-select-ui.open .role-form-select-trigger {
|
||||
border-color: var(--accent-color);
|
||||
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.16);
|
||||
}
|
||||
@@ -30192,6 +30817,149 @@ html[data-theme="dark"] #agent-md-modal .modal-content,
|
||||
html[data-theme="dark"] #agent-md-modal .modal-header,
|
||||
html[data-theme="dark"] #agent-md-modal .modal-body,
|
||||
html[data-theme="dark"] #agent-md-modal .modal-footer,
|
||||
.role-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;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-ui {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#role-modal .role-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;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-trigger:hover:not(:disabled) {
|
||||
border-color: rgba(59, 130, 246, 0.45);
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-ui.open .role-form-select-trigger {
|
||||
border-color: var(--accent-color);
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12);
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-ui.open {
|
||||
z-index: 120;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-ui.is-disabled .role-form-select-trigger {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-caret {
|
||||
flex-shrink: 0;
|
||||
color: var(--text-secondary);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-ui.open .role-form-select-caret {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-dropdown {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
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);
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-ui.open .role-form-select-dropdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#role-modal .role-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;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-option:hover {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-option.is-selected {
|
||||
background: rgba(59, 130, 246, 0.08);
|
||||
color: #2563eb;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-check {
|
||||
width: 14px;
|
||||
flex-shrink: 0;
|
||||
visibility: hidden;
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-option.is-selected .role-form-select-check {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#role-modal .role-form-select-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] #role-modal .modal-content,
|
||||
html[data-theme="dark"] #role-modal .modal-header,
|
||||
html[data-theme="dark"] #role-modal .modal-body,
|
||||
@@ -31787,6 +32555,152 @@ html[data-theme="dark"] .form-group select {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.workflow-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;
|
||||
}
|
||||
|
||||
.workflow-form-select-ui {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.workflow-binding-row .workflow-form-select-ui {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.workflow-form-select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-height: 38px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 7px;
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
font-size: 0.875rem;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.workflow-form-select-trigger:hover:not(:disabled) {
|
||||
border-color: rgba(59, 130, 246, 0.45);
|
||||
}
|
||||
|
||||
.workflow-form-select-ui.open .workflow-form-select-trigger {
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12);
|
||||
}
|
||||
|
||||
.workflow-form-select-ui.open {
|
||||
z-index: 120;
|
||||
}
|
||||
|
||||
.workflow-form-select-ui.is-disabled .workflow-form-select-trigger {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.workflow-form-select-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.workflow-form-select-caret {
|
||||
flex-shrink: 0;
|
||||
color: var(--text-secondary);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.workflow-form-select-ui.open .workflow-form-select-caret {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.workflow-form-select-dropdown {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
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);
|
||||
}
|
||||
|
||||
.workflow-form-select-ui.open .workflow-form-select-dropdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.workflow-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;
|
||||
}
|
||||
|
||||
.workflow-form-select-option:hover {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.workflow-form-select-option.is-selected {
|
||||
background: rgba(59, 130, 246, 0.08);
|
||||
color: #2563eb;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.workflow-form-select-check {
|
||||
width: 14px;
|
||||
flex-shrink: 0;
|
||||
visibility: hidden;
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.workflow-form-select-option.is-selected .workflow-form-select-check {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.workflow-form-select-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.workflow-tool-select {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
+167
-3
@@ -71,6 +71,162 @@
|
||||
return key;
|
||||
}
|
||||
|
||||
const c2FormSelectMap = {};
|
||||
let c2FormSelectDocBound = false;
|
||||
const C2_FORM_SELECT_CARET = '<svg class="c2-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>';
|
||||
const C2_FORM_SELECT_HANDLERS = {
|
||||
'c2-listener-type': function () {
|
||||
C2.syncListenerProfileRowForType();
|
||||
}
|
||||
};
|
||||
|
||||
function closeAllC2FormSelects() {
|
||||
Object.keys(c2FormSelectMap).forEach(function (id) {
|
||||
const reg = c2FormSelectMap[id];
|
||||
if (!reg || !reg.wrapper) return;
|
||||
reg.wrapper.classList.remove('open');
|
||||
if (reg.trigger) reg.trigger.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
|
||||
function syncC2FormSelect(selectId) {
|
||||
const reg = c2FormSelectMap[selectId];
|
||||
if (!reg) return;
|
||||
const select = reg.select;
|
||||
const dropdown = reg.dropdown;
|
||||
const trigger = reg.trigger;
|
||||
const valueSpan = trigger.querySelector('.c2-form-select-value');
|
||||
|
||||
dropdown.innerHTML = '';
|
||||
Array.prototype.forEach.call(select.options, function (opt) {
|
||||
const item = document.createElement('button');
|
||||
item.type = 'button';
|
||||
item.className = 'c2-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 = 'c2-form-select-check';
|
||||
check.setAttribute('aria-hidden', 'true');
|
||||
check.textContent = '✓';
|
||||
const label = document.createElement('span');
|
||||
label.className = 'c2-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 enhanceC2FormSelect(select) {
|
||||
if (!select || !select.id) return;
|
||||
const existing = c2FormSelectMap[select.id];
|
||||
if (existing && existing.select !== select) {
|
||||
delete c2FormSelectMap[select.id];
|
||||
}
|
||||
if (select.dataset.c2FormCustom === '1') {
|
||||
syncC2FormSelect(select.id);
|
||||
return;
|
||||
}
|
||||
select.dataset.c2FormCustom = '1';
|
||||
select.classList.add('c2-form-native-select');
|
||||
select.tabIndex = -1;
|
||||
select.setAttribute('aria-hidden', 'true');
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'c2-form-select-ui';
|
||||
|
||||
const trigger = document.createElement('button');
|
||||
trigger.type = 'button';
|
||||
trigger.className = 'c2-form-select-trigger';
|
||||
trigger.setAttribute('aria-haspopup', 'listbox');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
const valueSpan = document.createElement('span');
|
||||
valueSpan.className = 'c2-form-select-value';
|
||||
trigger.appendChild(valueSpan);
|
||||
trigger.insertAdjacentHTML('beforeend', C2_FORM_SELECT_CARET);
|
||||
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.className = 'c2-form-select-dropdown';
|
||||
dropdown.setAttribute('role', 'listbox');
|
||||
|
||||
const parent = select.parentNode;
|
||||
parent.insertBefore(wrapper, select);
|
||||
wrapper.appendChild(trigger);
|
||||
wrapper.appendChild(dropdown);
|
||||
wrapper.appendChild(select);
|
||||
|
||||
c2FormSelectMap[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');
|
||||
closeAllC2FormSelects();
|
||||
if (!open) {
|
||||
wrapper.classList.add('open');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click', function (e) {
|
||||
const opt = e.target.closest('.c2-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');
|
||||
syncC2FormSelect(select.id);
|
||||
});
|
||||
|
||||
select.addEventListener('change', function () {
|
||||
syncC2FormSelect(select.id);
|
||||
});
|
||||
|
||||
if (!select.dataset.c2FormFilterBound) {
|
||||
select.dataset.c2FormFilterBound = '1';
|
||||
const handler = C2_FORM_SELECT_HANDLERS[select.id];
|
||||
if (typeof handler === 'function') {
|
||||
select.addEventListener('change', handler);
|
||||
}
|
||||
}
|
||||
|
||||
syncC2FormSelect(select.id);
|
||||
}
|
||||
|
||||
C2.refreshFormSelects = function (root) {
|
||||
const container = root || document.getElementById('c2-modal-content');
|
||||
if (!container) return;
|
||||
Object.keys(c2FormSelectMap).forEach(function (id) {
|
||||
if (!document.getElementById(id)) delete c2FormSelectMap[id];
|
||||
});
|
||||
container.querySelectorAll('select.c2-form-select-native').forEach(enhanceC2FormSelect);
|
||||
if (!c2FormSelectDocBound) {
|
||||
c2FormSelectDocBound = true;
|
||||
document.addEventListener('click', closeAllC2FormSelects);
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') closeAllC2FormSelects();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function listenerTypeLabel(type) {
|
||||
if (!type) return '';
|
||||
const k = 'c2.listeners.typeLabels.' + String(type).toLowerCase();
|
||||
@@ -609,7 +765,7 @@
|
||||
</div>
|
||||
<div class="c2-form-group">
|
||||
<label>${escapeHtml(c2t('c2.listeners.type'))}</label>
|
||||
<select id="c2-listener-type" class="form-control c2-native-select" onchange="C2.syncListenerProfileRowForType()">
|
||||
<select id="c2-listener-type" class="form-control c2-form-select-native">
|
||||
<option value="http_beacon">HTTP Beacon</option>
|
||||
<option value="https_beacon">HTTPS Beacon</option>
|
||||
<option value="tcp_reverse">TCP Reverse</option>
|
||||
@@ -631,7 +787,7 @@
|
||||
<div class="c2-form-group" id="c2-listener-profile-group">
|
||||
<label>${escapeHtml(c2t('c2.listeners.malleableProfile'))}</label>
|
||||
${emptyProfHintCreate}
|
||||
<select id="c2-listener-profile-id" class="form-control c2-native-select">${profileOpts}</select>
|
||||
<select id="c2-listener-profile-id" class="form-control c2-form-select-native">${profileOpts}</select>
|
||||
<div class="form-hint">${escapeHtml(c2t('c2.listeners.malleableProfileHint'))}</div>
|
||||
</div>
|
||||
<div class="c2-form-group">
|
||||
@@ -657,6 +813,7 @@
|
||||
</div>
|
||||
`;
|
||||
C2.syncListenerProfileRowForType();
|
||||
C2.refreshFormSelects(content);
|
||||
}).catch(() => {
|
||||
showToast(c2t('c2.listeners.toastProfilesLoadFailed'), 'error');
|
||||
C2.closeModal();
|
||||
@@ -681,6 +838,8 @@
|
||||
if (legacyRow) {
|
||||
legacyRow.style.display = t === 'tcp_reverse' ? '' : 'none';
|
||||
}
|
||||
syncC2FormSelect('c2-listener-type');
|
||||
syncC2FormSelect('c2-listener-profile-id');
|
||||
};
|
||||
|
||||
C2.createListener = function() {
|
||||
@@ -801,7 +960,7 @@
|
||||
<div class="c2-form-group" id="c2-listener-profile-group">
|
||||
<label>${escapeHtml(c2t('c2.listeners.malleableProfile'))}</label>
|
||||
${httpHint}${emptyProfHint}
|
||||
<select id="c2-listener-profile-id" class="form-control c2-native-select">${profileOpts}</select>
|
||||
<select id="c2-listener-profile-id" class="form-control c2-form-select-native">${profileOpts}</select>
|
||||
<div class="form-hint">${escapeHtml(c2t('c2.listeners.malleableProfileHint'))}</div>
|
||||
</div>
|
||||
<div class="c2-form-group">
|
||||
@@ -827,6 +986,7 @@
|
||||
<button class="btn-primary" onclick="C2.saveListener('${l.id}')">${escapeHtml(c2t('common.save'))}</button>
|
||||
</div>
|
||||
`;
|
||||
C2.refreshFormSelects(content);
|
||||
}).catch(() => {
|
||||
showToast(c2t('c2.listeners.toastProfilesLoadFailed'), 'error');
|
||||
C2.closeModal();
|
||||
@@ -3580,6 +3740,7 @@
|
||||
};
|
||||
|
||||
C2.closeModal = function() {
|
||||
closeAllC2FormSelects();
|
||||
const modal = document.getElementById('c2-modal');
|
||||
if (modal) {
|
||||
const modalBox = modal.querySelector('.c2-modal');
|
||||
@@ -3619,6 +3780,9 @@
|
||||
if (!window.currentPageId || !String(window.currentPageId).startsWith('c2')) return;
|
||||
if (typeof applyTranslations === 'function') applyTranslations(document);
|
||||
C2.init();
|
||||
if (isAppModalOpen('c2-modal')) {
|
||||
C2.refreshFormSelects();
|
||||
}
|
||||
if (C2.selectedSessionId && (window.currentPageId === 'c2-sessions')) {
|
||||
C2.renderSessions();
|
||||
C2.renderSessionDetail(C2.selectedSessionId);
|
||||
|
||||
@@ -17,6 +17,156 @@ let chatFilesPendingUploadDir = '';
|
||||
/** 文件管理页面向服务器上传进行中,避免重复选择并禁用顶栏按钮 */
|
||||
let chatFilesXHRUploadBusy = false;
|
||||
|
||||
const CHAT_FILES_FILTER_SELECT_IDS = ['chat-files-group-by'];
|
||||
const chatFilesFilterSelectMap = {};
|
||||
let chatFilesFilterSelectDocBound = false;
|
||||
const CHAT_FILES_FILTER_SELECT_CARET = '<svg class="chat-files-filter-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 closeAllChatFilesFilterSelects() {
|
||||
Object.keys(chatFilesFilterSelectMap).forEach(function (id) {
|
||||
const reg = chatFilesFilterSelectMap[id];
|
||||
if (!reg || !reg.wrapper) return;
|
||||
reg.wrapper.classList.remove('open');
|
||||
if (reg.trigger) reg.trigger.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
|
||||
function syncChatFilesFilterSelect(selectId) {
|
||||
const reg = chatFilesFilterSelectMap[selectId];
|
||||
if (!reg) return;
|
||||
const select = reg.select;
|
||||
const dropdown = reg.dropdown;
|
||||
const trigger = reg.trigger;
|
||||
const valueSpan = trigger.querySelector('.chat-files-filter-select-value');
|
||||
|
||||
dropdown.innerHTML = '';
|
||||
Array.prototype.forEach.call(select.options, function (opt) {
|
||||
const item = document.createElement('button');
|
||||
item.type = 'button';
|
||||
item.className = 'chat-files-filter-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 = 'chat-files-filter-select-check';
|
||||
check.setAttribute('aria-hidden', 'true');
|
||||
check.textContent = '✓';
|
||||
const label = document.createElement('span');
|
||||
label.className = 'chat-files-filter-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 syncAllChatFilesFilterSelects() {
|
||||
CHAT_FILES_FILTER_SELECT_IDS.forEach(syncChatFilesFilterSelect);
|
||||
}
|
||||
|
||||
function enhanceChatFilesFilterSelect(selectId) {
|
||||
const select = document.getElementById(selectId);
|
||||
if (!select) return;
|
||||
const existing = chatFilesFilterSelectMap[selectId];
|
||||
if (existing && existing.select !== select) {
|
||||
delete chatFilesFilterSelectMap[selectId];
|
||||
}
|
||||
if (select.dataset.chatFilesCustomSelect === '1') {
|
||||
syncChatFilesFilterSelect(selectId);
|
||||
return;
|
||||
}
|
||||
select.dataset.chatFilesCustomSelect = '1';
|
||||
select.classList.add('chat-files-filter-native-select');
|
||||
select.tabIndex = -1;
|
||||
select.setAttribute('aria-hidden', 'true');
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'chat-files-filter-select-ui';
|
||||
|
||||
const trigger = document.createElement('button');
|
||||
trigger.type = 'button';
|
||||
trigger.className = 'chat-files-filter-select-trigger';
|
||||
trigger.setAttribute('aria-haspopup', 'listbox');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
const valueSpan = document.createElement('span');
|
||||
valueSpan.className = 'chat-files-filter-select-value';
|
||||
trigger.appendChild(valueSpan);
|
||||
trigger.insertAdjacentHTML('beforeend', CHAT_FILES_FILTER_SELECT_CARET);
|
||||
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.className = 'chat-files-filter-select-dropdown';
|
||||
dropdown.setAttribute('role', 'listbox');
|
||||
|
||||
const parent = select.parentNode;
|
||||
parent.insertBefore(wrapper, select);
|
||||
wrapper.appendChild(trigger);
|
||||
wrapper.appendChild(dropdown);
|
||||
wrapper.appendChild(select);
|
||||
|
||||
chatFilesFilterSelectMap[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');
|
||||
closeAllChatFilesFilterSelects();
|
||||
if (!open) {
|
||||
wrapper.classList.add('open');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click', function (e) {
|
||||
const opt = e.target.closest('.chat-files-filter-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');
|
||||
syncChatFilesFilterSelect(selectId);
|
||||
});
|
||||
|
||||
select.addEventListener('change', function () {
|
||||
syncChatFilesFilterSelect(selectId);
|
||||
});
|
||||
|
||||
if (!select.dataset.chatFilesFilterBound) {
|
||||
select.dataset.chatFilesFilterBound = '1';
|
||||
select.addEventListener('change', chatFilesGroupByChange);
|
||||
}
|
||||
|
||||
syncChatFilesFilterSelect(selectId);
|
||||
}
|
||||
|
||||
function initChatFilesFilterSelects() {
|
||||
if (!chatFilesFilterSelectDocBound) {
|
||||
document.addEventListener('click', closeAllChatFilesFilterSelects);
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') closeAllChatFilesFilterSelects();
|
||||
});
|
||||
chatFilesFilterSelectDocBound = true;
|
||||
}
|
||||
CHAT_FILES_FILTER_SELECT_IDS.forEach(enhanceChatFilesFilterSelect);
|
||||
syncAllChatFilesFilterSelects();
|
||||
}
|
||||
|
||||
function chatFilesLoadBrowsePathFromStorage() {
|
||||
try {
|
||||
const raw = localStorage.getItem(CHAT_FILES_BROWSE_PATH_KEY);
|
||||
@@ -84,6 +234,7 @@ function initChatFilesPage() {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
initChatFilesFilterSelects();
|
||||
setupChatFilesDragDrop();
|
||||
loadChatFilesPage();
|
||||
}
|
||||
@@ -1349,7 +1500,12 @@ function setupChatFilesDragDrop() {
|
||||
document.addEventListener('languagechange', function () {
|
||||
if (typeof window.currentPage !== 'function') return;
|
||||
if (window.currentPage() !== 'chat-files') return;
|
||||
syncAllChatFilesFilterSelects();
|
||||
if (typeof renderChatFilesTable === 'function') {
|
||||
renderChatFilesTable();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
initChatFilesFilterSelects();
|
||||
});
|
||||
|
||||
@@ -1145,6 +1145,158 @@ function hitlFormatTime(v) {
|
||||
}
|
||||
}
|
||||
|
||||
const HITL_LOG_FILTER_SELECT_IDS = ['hitl-logs-decision-filter', 'hitl-logs-decidedby-filter'];
|
||||
const hitlLogFilterSelectMap = {};
|
||||
let hitlLogFilterSelectDocBound = false;
|
||||
|
||||
const HITL_FILTER_SELECT_CARET = '<svg class="hitl-filter-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 closeAllHitlLogFilterSelects() {
|
||||
Object.keys(hitlLogFilterSelectMap).forEach(function (id) {
|
||||
const reg = hitlLogFilterSelectMap[id];
|
||||
if (!reg || !reg.wrapper) return;
|
||||
reg.wrapper.classList.remove('open');
|
||||
if (reg.trigger) reg.trigger.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
|
||||
function syncHitlLogFilterSelect(selectId) {
|
||||
const reg = hitlLogFilterSelectMap[selectId];
|
||||
if (!reg) return;
|
||||
const select = reg.select;
|
||||
const dropdown = reg.dropdown;
|
||||
const trigger = reg.trigger;
|
||||
const valueSpan = trigger.querySelector('.hitl-filter-select-value');
|
||||
|
||||
dropdown.innerHTML = '';
|
||||
Array.prototype.forEach.call(select.options, function (opt) {
|
||||
const item = document.createElement('button');
|
||||
item.type = 'button';
|
||||
item.className = 'hitl-filter-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 = 'hitl-filter-select-check';
|
||||
check.setAttribute('aria-hidden', 'true');
|
||||
check.textContent = '✓';
|
||||
const label = document.createElement('span');
|
||||
label.className = 'hitl-filter-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 syncAllHitlLogFilterSelects() {
|
||||
HITL_LOG_FILTER_SELECT_IDS.forEach(syncHitlLogFilterSelect);
|
||||
}
|
||||
|
||||
function enhanceHitlLogFilterSelect(selectId) {
|
||||
const select = document.getElementById(selectId);
|
||||
if (!select) return;
|
||||
if (select.dataset.hitlCustomSelect === '1') {
|
||||
syncHitlLogFilterSelect(selectId);
|
||||
return;
|
||||
}
|
||||
select.dataset.hitlCustomSelect = '1';
|
||||
select.classList.add('hitl-filter-native-select');
|
||||
select.tabIndex = -1;
|
||||
select.setAttribute('aria-hidden', 'true');
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'hitl-filter-select-ui';
|
||||
if (selectId === 'hitl-logs-decision-filter') {
|
||||
wrapper.classList.add('hitl-filter-select-ui--decision');
|
||||
} else if (selectId === 'hitl-logs-decidedby-filter') {
|
||||
wrapper.classList.add('hitl-filter-select-ui--decidedby');
|
||||
}
|
||||
|
||||
const trigger = document.createElement('button');
|
||||
trigger.type = 'button';
|
||||
trigger.className = 'hitl-filter-select-trigger';
|
||||
trigger.setAttribute('aria-haspopup', 'listbox');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
const valueSpan = document.createElement('span');
|
||||
valueSpan.className = 'hitl-filter-select-value';
|
||||
trigger.appendChild(valueSpan);
|
||||
trigger.insertAdjacentHTML('beforeend', HITL_FILTER_SELECT_CARET);
|
||||
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.className = 'hitl-filter-select-dropdown';
|
||||
dropdown.setAttribute('role', 'listbox');
|
||||
|
||||
const parent = select.parentNode;
|
||||
parent.insertBefore(wrapper, select);
|
||||
wrapper.appendChild(trigger);
|
||||
wrapper.appendChild(dropdown);
|
||||
wrapper.appendChild(select);
|
||||
|
||||
hitlLogFilterSelectMap[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');
|
||||
closeAllHitlLogFilterSelects();
|
||||
if (!open) {
|
||||
wrapper.classList.add('open');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click', function (e) {
|
||||
const opt = e.target.closest('.hitl-filter-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');
|
||||
syncHitlLogFilterSelect(selectId);
|
||||
});
|
||||
|
||||
select.addEventListener('change', function () {
|
||||
syncHitlLogFilterSelect(selectId);
|
||||
});
|
||||
}
|
||||
|
||||
function initHitlLogFilterSelects() {
|
||||
if (!hitlLogFilterSelectDocBound) {
|
||||
document.addEventListener('click', closeAllHitlLogFilterSelects);
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') closeAllHitlLogFilterSelects();
|
||||
});
|
||||
hitlLogFilterSelectDocBound = true;
|
||||
}
|
||||
HITL_LOG_FILTER_SELECT_IDS.forEach(function (id) {
|
||||
enhanceHitlLogFilterSelect(id);
|
||||
const select = document.getElementById(id);
|
||||
if (select && !select.dataset.hitlFilterBound) {
|
||||
select.dataset.hitlFilterBound = '1';
|
||||
select.addEventListener('change', filterHitlLogs);
|
||||
}
|
||||
});
|
||||
syncAllHitlLogFilterSelects();
|
||||
}
|
||||
|
||||
function hitlLogsHasActiveFilters() {
|
||||
const qEl = document.getElementById('hitl-logs-search');
|
||||
const decEl = document.getElementById('hitl-logs-decision-filter');
|
||||
@@ -1432,6 +1584,7 @@ function refreshHitlPendingI18n() {
|
||||
function refreshHitlI18n() {
|
||||
refreshHitlLogsI18n();
|
||||
refreshHitlPendingI18n();
|
||||
syncAllHitlLogFilterSelects();
|
||||
renderHitlLogsPagination();
|
||||
renderHitlPendingPagination();
|
||||
}
|
||||
@@ -1619,6 +1772,7 @@ window.addEventListener('pageshow', function () {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
initHitlPageSizeFromStorage(HITL_LOGS_PAGE_SIZE_KEY, 20, function (n) { hitlLogsPageSize = n; });
|
||||
initHitlPageSizeFromStorage(HITL_PENDING_PAGE_SIZE_KEY, 20, function (n) { hitlPendingPageSize = n; });
|
||||
initHitlLogFilterSelects();
|
||||
if (typeof window.bindHitlReviewerToggleListeners === 'function') {
|
||||
window.bindHitlReviewerToggleListeners();
|
||||
}
|
||||
|
||||
+191
-1
@@ -26,6 +26,189 @@ function tpFmt(key, fallback, opts) {
|
||||
return text;
|
||||
}
|
||||
|
||||
function tpFmt(key, fallback, opts) {
|
||||
const text = tp(key, opts);
|
||||
if (!text || text === key) return fallback;
|
||||
return text;
|
||||
}
|
||||
|
||||
const PROJECTS_FILTER_SELECT_HANDLERS = {
|
||||
'project-facts-filter-category': function () { loadProjectFacts(); },
|
||||
'project-facts-filter-confidence': function () { loadProjectFacts(); },
|
||||
'project-graph-view': function () { loadProjectFactGraph(); },
|
||||
'project-vulns-filter-severity': function () { loadProjectVulnerabilities(); },
|
||||
'project-vulns-filter-status': function () { loadProjectVulnerabilities(); },
|
||||
'projects-page-size-pagination': function () { changeProjectsPageSize(); }
|
||||
};
|
||||
const projectsFilterSelectMap = {};
|
||||
let projectsFilterSelectDocBound = false;
|
||||
const PROJECTS_FILTER_SELECT_CARET = '<svg class="projects-filter-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 closeAllProjectsFilterSelects() {
|
||||
Object.keys(projectsFilterSelectMap).forEach(function (id) {
|
||||
const reg = projectsFilterSelectMap[id];
|
||||
if (!reg || !reg.wrapper) return;
|
||||
reg.wrapper.classList.remove('open');
|
||||
if (reg.trigger) reg.trigger.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
|
||||
function pruneProjectsFilterSelectMap(root) {
|
||||
Object.keys(projectsFilterSelectMap).forEach(function (id) {
|
||||
const select = document.getElementById(id);
|
||||
if (!select || (root && !root.contains(select))) {
|
||||
delete projectsFilterSelectMap[id];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function syncProjectsFilterSelect(select) {
|
||||
const reg = projectsFilterSelectMap[select.id];
|
||||
if (!reg) return;
|
||||
const dropdown = reg.dropdown;
|
||||
const trigger = reg.trigger;
|
||||
const valueSpan = trigger.querySelector('.projects-filter-select-value');
|
||||
|
||||
dropdown.innerHTML = '';
|
||||
Array.prototype.forEach.call(select.options, function (opt) {
|
||||
const item = document.createElement('button');
|
||||
item.type = 'button';
|
||||
item.className = 'projects-filter-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 = 'projects-filter-select-check';
|
||||
check.setAttribute('aria-hidden', 'true');
|
||||
check.textContent = '✓';
|
||||
const label = document.createElement('span');
|
||||
label.className = 'projects-filter-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 syncAllProjectsFilterSelects() {
|
||||
Object.keys(projectsFilterSelectMap).forEach(function (id) {
|
||||
const select = document.getElementById(id);
|
||||
if (select) syncProjectsFilterSelect(select);
|
||||
});
|
||||
}
|
||||
|
||||
function enhanceProjectsFilterSelect(select) {
|
||||
if (!select || !select.id) return;
|
||||
const existing = projectsFilterSelectMap[select.id];
|
||||
if (existing && existing.select !== select) {
|
||||
delete projectsFilterSelectMap[select.id];
|
||||
}
|
||||
if (select.dataset.projectsCustomSelect === '1') {
|
||||
syncProjectsFilterSelect(select);
|
||||
return;
|
||||
}
|
||||
select.dataset.projectsCustomSelect = '1';
|
||||
select.classList.add('projects-filter-native-select');
|
||||
select.tabIndex = -1;
|
||||
select.setAttribute('aria-hidden', 'true');
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'projects-filter-select-ui';
|
||||
if (select.id === 'projects-page-size-pagination') {
|
||||
wrapper.classList.add('projects-filter-select-ui--compact');
|
||||
}
|
||||
|
||||
const trigger = document.createElement('button');
|
||||
trigger.type = 'button';
|
||||
trigger.className = 'projects-filter-select-trigger';
|
||||
trigger.setAttribute('aria-haspopup', 'listbox');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
const valueSpan = document.createElement('span');
|
||||
valueSpan.className = 'projects-filter-select-value';
|
||||
trigger.appendChild(valueSpan);
|
||||
trigger.insertAdjacentHTML('beforeend', PROJECTS_FILTER_SELECT_CARET);
|
||||
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.className = 'projects-filter-select-dropdown';
|
||||
dropdown.setAttribute('role', 'listbox');
|
||||
|
||||
const parent = select.parentNode;
|
||||
parent.insertBefore(wrapper, select);
|
||||
wrapper.appendChild(trigger);
|
||||
wrapper.appendChild(dropdown);
|
||||
wrapper.appendChild(select);
|
||||
|
||||
projectsFilterSelectMap[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');
|
||||
closeAllProjectsFilterSelects();
|
||||
if (!open) {
|
||||
wrapper.classList.add('open');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click', function (e) {
|
||||
const opt = e.target.closest('.projects-filter-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');
|
||||
syncProjectsFilterSelect(select);
|
||||
});
|
||||
|
||||
select.addEventListener('change', function () {
|
||||
syncProjectsFilterSelect(select);
|
||||
});
|
||||
|
||||
if (!select.dataset.projectsFilterBound) {
|
||||
select.dataset.projectsFilterBound = '1';
|
||||
const handler = PROJECTS_FILTER_SELECT_HANDLERS[select.id];
|
||||
if (typeof handler === 'function') {
|
||||
select.addEventListener('change', handler);
|
||||
}
|
||||
}
|
||||
|
||||
syncProjectsFilterSelect(select);
|
||||
}
|
||||
|
||||
function refreshProjectsFilterSelects() {
|
||||
const page = document.getElementById('page-projects');
|
||||
if (!page) return;
|
||||
pruneProjectsFilterSelectMap(page);
|
||||
page.querySelectorAll('select.projects-filter-select-native, #projects-page-size-pagination').forEach(function (select) {
|
||||
enhanceProjectsFilterSelect(select);
|
||||
});
|
||||
if (!projectsFilterSelectDocBound) {
|
||||
projectsFilterSelectDocBound = true;
|
||||
document.addEventListener('click', closeAllProjectsFilterSelects);
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') closeAllProjectsFilterSelects();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** 与后端 internal/project/fact_template.go 对齐 */
|
||||
const FACT_ATTACK_CHAIN_BODY_TEMPLATE = `## 结论(可验证,一句话)
|
||||
<勿仅写「存在漏洞」;写明类型 + 位置 + 触发条件>
|
||||
@@ -404,6 +587,7 @@ async function initProjectsPage() {
|
||||
const page = document.getElementById('page-projects');
|
||||
if (!page || page.style.display === 'none') return;
|
||||
initProjectsModalEscape();
|
||||
refreshProjectsFilterSelects();
|
||||
if (typeof syncAppModalBodyLock === 'function') {
|
||||
syncAppModalBodyLock();
|
||||
}
|
||||
@@ -638,13 +822,14 @@ function renderProjectsPagination() {
|
||||
</div>
|
||||
<label class="pagination-page-size">
|
||||
${escapeHtml(tp('projects.paginationPerPage'))}
|
||||
<select id="projects-page-size-pagination" onchange="changeProjectsPageSize()">
|
||||
<select id="projects-page-size-pagination" class="projects-filter-select-native">
|
||||
<option value="20" ${pageSize === 20 ? 'selected' : ''}>20</option>
|
||||
<option value="50" ${pageSize === 50 ? 'selected' : ''}>50</option>
|
||||
<option value="100" ${pageSize === 100 ? 'selected' : ''}>100</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>`;
|
||||
refreshProjectsFilterSelects();
|
||||
}
|
||||
|
||||
function renderProjectsSidebar() {
|
||||
@@ -780,6 +965,7 @@ async function selectProject(id) {
|
||||
if (vulnSearchEl) vulnSearchEl.value = '';
|
||||
if (vulnSevEl) vulnSevEl.value = '';
|
||||
if (vulnStatusEl) vulnStatusEl.value = '';
|
||||
syncAllProjectsFilterSelects();
|
||||
renderProjectsSidebar();
|
||||
updateProjectsDetailVisibility();
|
||||
try {
|
||||
@@ -792,6 +978,7 @@ async function selectProject(id) {
|
||||
document.getElementById('project-edit-scope').value = p.scope_json || '';
|
||||
const statusEl = document.getElementById('project-edit-status');
|
||||
if (statusEl) statusEl.value = p.status || 'active';
|
||||
syncAllProjectsFilterSelects();
|
||||
const pinEl = document.getElementById('project-edit-pinned');
|
||||
if (pinEl) pinEl.checked = !!p.pinned;
|
||||
updateProjectStatusPill(p.status || 'active');
|
||||
@@ -2427,6 +2614,7 @@ function initChatProjectSelector() {
|
||||
document.addEventListener('languagechange', () => {
|
||||
renderProjectsSidebar();
|
||||
renderProjectsPagination();
|
||||
syncAllProjectsFilterSelects();
|
||||
updateChatProjectButtonLabel();
|
||||
const panel = document.getElementById('chat-project-panel');
|
||||
if (panel && panel.style.display === 'flex') loadChatProjectPanelList();
|
||||
@@ -2455,10 +2643,12 @@ if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initChatProjectSelector();
|
||||
initProjectListActionMenu();
|
||||
refreshProjectsFilterSelects();
|
||||
});
|
||||
} else {
|
||||
initChatProjectSelector();
|
||||
initProjectListActionMenu();
|
||||
refreshProjectsFilterSelects();
|
||||
}
|
||||
|
||||
window.initProjectsPage = initProjectsPage;
|
||||
|
||||
@@ -17,6 +17,155 @@ function _t(key, opts) {
|
||||
return key;
|
||||
}
|
||||
|
||||
const ROLE_MODAL_SELECT_IDS = ['role-workflow-id', 'role-workflow-policy'];
|
||||
const roleModalSelectMap = {};
|
||||
let roleModalSelectDocBound = false;
|
||||
const ROLE_FORM_SELECT_CARET = '<svg class="role-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 closeAllRoleModalSelects() {
|
||||
Object.keys(roleModalSelectMap).forEach(function (id) {
|
||||
const reg = roleModalSelectMap[id];
|
||||
if (!reg || !reg.wrapper) return;
|
||||
reg.wrapper.classList.remove('open');
|
||||
if (reg.trigger) reg.trigger.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
|
||||
function syncRoleModalSelect(selectId) {
|
||||
const reg = roleModalSelectMap[selectId];
|
||||
if (!reg) return;
|
||||
const select = reg.select;
|
||||
const dropdown = reg.dropdown;
|
||||
const trigger = reg.trigger;
|
||||
const valueSpan = trigger.querySelector('.role-form-select-value');
|
||||
|
||||
dropdown.innerHTML = '';
|
||||
Array.prototype.forEach.call(select.options, function (opt) {
|
||||
const item = document.createElement('button');
|
||||
item.type = 'button';
|
||||
item.className = 'role-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 = 'role-form-select-check';
|
||||
check.setAttribute('aria-hidden', 'true');
|
||||
check.textContent = '✓';
|
||||
const label = document.createElement('span');
|
||||
label.className = 'role-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 syncAllRoleModalSelects() {
|
||||
ROLE_MODAL_SELECT_IDS.forEach(syncRoleModalSelect);
|
||||
}
|
||||
|
||||
function enhanceRoleModalSelect(selectId) {
|
||||
const select = document.getElementById(selectId);
|
||||
if (!select) return;
|
||||
const existing = roleModalSelectMap[selectId];
|
||||
if (existing && existing.select !== select) {
|
||||
delete roleModalSelectMap[selectId];
|
||||
}
|
||||
if (select.dataset.roleFormCustom === '1') {
|
||||
syncRoleModalSelect(selectId);
|
||||
return;
|
||||
}
|
||||
select.dataset.roleFormCustom = '1';
|
||||
select.classList.add('role-form-native-select');
|
||||
select.tabIndex = -1;
|
||||
select.setAttribute('aria-hidden', 'true');
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'role-form-select-ui';
|
||||
|
||||
const trigger = document.createElement('button');
|
||||
trigger.type = 'button';
|
||||
trigger.className = 'role-form-select-trigger';
|
||||
trigger.setAttribute('aria-haspopup', 'listbox');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
const valueSpan = document.createElement('span');
|
||||
valueSpan.className = 'role-form-select-value';
|
||||
trigger.appendChild(valueSpan);
|
||||
trigger.insertAdjacentHTML('beforeend', ROLE_FORM_SELECT_CARET);
|
||||
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.className = 'role-form-select-dropdown';
|
||||
dropdown.setAttribute('role', 'listbox');
|
||||
|
||||
const parent = select.parentNode;
|
||||
parent.insertBefore(wrapper, select);
|
||||
wrapper.appendChild(trigger);
|
||||
wrapper.appendChild(dropdown);
|
||||
wrapper.appendChild(select);
|
||||
|
||||
roleModalSelectMap[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');
|
||||
closeAllRoleModalSelects();
|
||||
if (!open) {
|
||||
wrapper.classList.add('open');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click', function (e) {
|
||||
const opt = e.target.closest('.role-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');
|
||||
syncRoleModalSelect(selectId);
|
||||
});
|
||||
|
||||
select.addEventListener('change', function () {
|
||||
syncRoleModalSelect(selectId);
|
||||
});
|
||||
|
||||
syncRoleModalSelect(selectId);
|
||||
}
|
||||
|
||||
function refreshRoleModalSelects() {
|
||||
const modal = document.getElementById('role-modal');
|
||||
if (!modal) return;
|
||||
Object.keys(roleModalSelectMap).forEach(function (id) {
|
||||
if (!document.getElementById(id)) delete roleModalSelectMap[id];
|
||||
});
|
||||
ROLE_MODAL_SELECT_IDS.forEach(enhanceRoleModalSelect);
|
||||
if (!roleModalSelectDocBound) {
|
||||
roleModalSelectDocBound = true;
|
||||
document.addEventListener('click', closeAllRoleModalSelects);
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') closeAllRoleModalSelects();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** 角色配置中的描述:trim,并把误存为 i18n key 的字面量视为空 */
|
||||
function rolePlainDescription(role) {
|
||||
const raw = typeof role.description === 'string' ? role.description.trim() : '';
|
||||
@@ -1201,6 +1350,7 @@ async function showAddRoleModal() {
|
||||
// 确保统计信息正确更新(显示0/108)
|
||||
updateRoleToolsStats();
|
||||
|
||||
refreshRoleModalSelects();
|
||||
openAppModal('role-modal');
|
||||
}
|
||||
|
||||
@@ -1370,11 +1520,13 @@ async function editRole(roleName) {
|
||||
}
|
||||
}
|
||||
|
||||
refreshRoleModalSelects();
|
||||
openAppModal('role-modal');
|
||||
}
|
||||
|
||||
// 关闭角色模态框
|
||||
function closeRoleModal() {
|
||||
closeAllRoleModalSelects();
|
||||
closeAppModal('role-modal');
|
||||
}
|
||||
|
||||
@@ -1720,12 +1872,14 @@ document.addEventListener('click', (e) => {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
loadRoles();
|
||||
updateRoleSelectorDisplay();
|
||||
refreshRoleModalSelects();
|
||||
});
|
||||
|
||||
// 语言切换后刷新角色选择器与「选择角色」列表文案
|
||||
document.addEventListener('languagechange', () => {
|
||||
updateRoleSelectorDisplay();
|
||||
renderRoleSelectionSidebar();
|
||||
syncAllRoleModalSelects();
|
||||
});
|
||||
|
||||
// 获取当前选中的角色(供chat.js使用)
|
||||
@@ -1740,6 +1894,7 @@ if (typeof window !== 'undefined') {
|
||||
window.closeRoleSelectionPanel = closeRoleSelectionPanel;
|
||||
window.closeRoleSelectModal = closeRoleSelectModal;
|
||||
window.filterRoleToolsByStatus = filterRoleToolsByStatus;
|
||||
window.refreshRoleModalSelects = refreshRoleModalSelects;
|
||||
window.currentSelectedRole = getCurrentRole();
|
||||
|
||||
// 监听角色变化,更新全局变量
|
||||
|
||||
@@ -764,6 +764,7 @@ function toggleTasksAutoRefresh(enabled) {
|
||||
|
||||
// 初始化任务管理页面
|
||||
function initTasksPage() {
|
||||
initBatchQueuesFilterSelects();
|
||||
// 恢复自动刷新设置
|
||||
const autoRefreshCheckbox = document.getElementById('tasks-auto-refresh');
|
||||
if (autoRefreshCheckbox) {
|
||||
@@ -1151,6 +1152,153 @@ async function loadBatchQueues(page) {
|
||||
}
|
||||
}
|
||||
|
||||
const BATCH_QUEUES_FILTER_SELECT_IDS = ['batch-queues-status-filter'];
|
||||
const batchQueuesFilterSelectMap = {};
|
||||
let batchQueuesFilterSelectDocBound = false;
|
||||
|
||||
const TASKS_FILTER_SELECT_CARET = '<svg class="tasks-filter-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 closeAllBatchQueuesFilterSelects() {
|
||||
Object.keys(batchQueuesFilterSelectMap).forEach(function (id) {
|
||||
const reg = batchQueuesFilterSelectMap[id];
|
||||
if (!reg || !reg.wrapper) return;
|
||||
reg.wrapper.classList.remove('open');
|
||||
if (reg.trigger) reg.trigger.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
|
||||
function syncBatchQueuesFilterSelect(selectId) {
|
||||
const reg = batchQueuesFilterSelectMap[selectId];
|
||||
if (!reg) return;
|
||||
const select = reg.select;
|
||||
const dropdown = reg.dropdown;
|
||||
const trigger = reg.trigger;
|
||||
const valueSpan = trigger.querySelector('.tasks-filter-select-value');
|
||||
|
||||
dropdown.innerHTML = '';
|
||||
Array.prototype.forEach.call(select.options, function (opt) {
|
||||
const item = document.createElement('button');
|
||||
item.type = 'button';
|
||||
item.className = 'tasks-filter-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 = 'tasks-filter-select-check';
|
||||
check.setAttribute('aria-hidden', 'true');
|
||||
check.textContent = '✓';
|
||||
const label = document.createElement('span');
|
||||
label.className = 'tasks-filter-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 syncAllBatchQueuesFilterSelects() {
|
||||
BATCH_QUEUES_FILTER_SELECT_IDS.forEach(syncBatchQueuesFilterSelect);
|
||||
}
|
||||
|
||||
function enhanceBatchQueuesFilterSelect(selectId) {
|
||||
const select = document.getElementById(selectId);
|
||||
if (!select) return;
|
||||
if (select.dataset.tasksCustomSelect === '1') {
|
||||
syncBatchQueuesFilterSelect(selectId);
|
||||
return;
|
||||
}
|
||||
select.dataset.tasksCustomSelect = '1';
|
||||
select.classList.add('tasks-filter-native-select');
|
||||
select.tabIndex = -1;
|
||||
select.setAttribute('aria-hidden', 'true');
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'tasks-filter-select-ui';
|
||||
|
||||
const trigger = document.createElement('button');
|
||||
trigger.type = 'button';
|
||||
trigger.className = 'tasks-filter-select-trigger';
|
||||
trigger.setAttribute('aria-haspopup', 'listbox');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
const valueSpan = document.createElement('span');
|
||||
valueSpan.className = 'tasks-filter-select-value';
|
||||
trigger.appendChild(valueSpan);
|
||||
trigger.insertAdjacentHTML('beforeend', TASKS_FILTER_SELECT_CARET);
|
||||
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.className = 'tasks-filter-select-dropdown';
|
||||
dropdown.setAttribute('role', 'listbox');
|
||||
|
||||
const parent = select.parentNode;
|
||||
parent.insertBefore(wrapper, select);
|
||||
wrapper.appendChild(trigger);
|
||||
wrapper.appendChild(dropdown);
|
||||
wrapper.appendChild(select);
|
||||
|
||||
batchQueuesFilterSelectMap[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');
|
||||
closeAllBatchQueuesFilterSelects();
|
||||
if (!open) {
|
||||
wrapper.classList.add('open');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click', function (e) {
|
||||
const opt = e.target.closest('.tasks-filter-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');
|
||||
syncBatchQueuesFilterSelect(selectId);
|
||||
});
|
||||
|
||||
select.addEventListener('change', function () {
|
||||
syncBatchQueuesFilterSelect(selectId);
|
||||
});
|
||||
}
|
||||
|
||||
function initBatchQueuesFilterSelects() {
|
||||
if (!batchQueuesFilterSelectDocBound) {
|
||||
document.addEventListener('click', closeAllBatchQueuesFilterSelects);
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') closeAllBatchQueuesFilterSelects();
|
||||
});
|
||||
batchQueuesFilterSelectDocBound = true;
|
||||
}
|
||||
BATCH_QUEUES_FILTER_SELECT_IDS.forEach(function (id) {
|
||||
enhanceBatchQueuesFilterSelect(id);
|
||||
const select = document.getElementById(id);
|
||||
if (select && !select.dataset.tasksFilterBound) {
|
||||
select.dataset.tasksFilterBound = '1';
|
||||
select.addEventListener('change', filterBatchQueues);
|
||||
}
|
||||
});
|
||||
syncAllBatchQueuesFilterSelects();
|
||||
}
|
||||
|
||||
// 筛选批量任务队列
|
||||
function filterBatchQueues() {
|
||||
const statusFilter = document.getElementById('batch-queues-status-filter');
|
||||
@@ -2526,6 +2674,7 @@ window.saveInlineSchedule = saveInlineSchedule;
|
||||
// 语言切换后,列表/分页/详情弹窗由 JS 渲染的文案需用当前语言重绘(applyTranslations 不会处理 innerHTML 内容)
|
||||
document.addEventListener('languagechange', function () {
|
||||
try {
|
||||
syncAllBatchQueuesFilterSelects();
|
||||
const tasksPage = document.getElementById('page-tasks');
|
||||
if (!tasksPage || !tasksPage.classList.contains('active')) {
|
||||
return;
|
||||
@@ -2545,3 +2694,7 @@ document.addEventListener('languagechange', function () {
|
||||
console.warn('languagechange tasks refresh failed', e);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
initBatchQueuesFilterSelects();
|
||||
});
|
||||
|
||||
+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() {
|
||||
|
||||
+13
-13
@@ -1271,7 +1271,7 @@
|
||||
</label>
|
||||
<label>
|
||||
<span data-i18n="hitl.filterDecision">决策</span>
|
||||
<select id="hitl-logs-decision-filter" class="hitl-filter-select" onchange="filterHitlLogs()">
|
||||
<select id="hitl-logs-decision-filter" class="hitl-filter-select">
|
||||
<option value="all" data-i18n="hitl.filterAll">全部</option>
|
||||
<option value="approve" data-i18n="hitl.decisionApprove">通过</option>
|
||||
<option value="reject" data-i18n="hitl.decisionReject">拒绝</option>
|
||||
@@ -1279,7 +1279,7 @@
|
||||
</label>
|
||||
<label>
|
||||
<span data-i18n="hitl.filterDecidedBy">审批方</span>
|
||||
<select id="hitl-logs-decidedby-filter" class="hitl-filter-select" onchange="filterHitlLogs()">
|
||||
<select id="hitl-logs-decidedby-filter" class="hitl-filter-select">
|
||||
<option value="all" data-i18n="hitl.filterAll">全部</option>
|
||||
<option value="human" data-i18n="hitl.reviewerHuman">人工</option>
|
||||
<option value="audit_agent" data-i18n="hitl.reviewerAgent">审计 Agent</option>
|
||||
@@ -1795,7 +1795,7 @@
|
||||
</label>
|
||||
<label class="projects-fact-filter-field">
|
||||
<span class="projects-fact-filter-label" data-i18n="projects.category">分类</span>
|
||||
<select id="project-facts-filter-category" onchange="loadProjectFacts()">
|
||||
<select id="project-facts-filter-category" class="projects-filter-select-native">
|
||||
<option value="" data-i18n="projects.all">全部</option>
|
||||
<option value="target">target</option>
|
||||
<option value="auth">auth</option>
|
||||
@@ -1810,7 +1810,7 @@
|
||||
</label>
|
||||
<label class="projects-fact-filter-field">
|
||||
<span class="projects-fact-filter-label" data-i18n="projects.confidence">置信度</span>
|
||||
<select id="project-facts-filter-confidence" onchange="loadProjectFacts()">
|
||||
<select id="project-facts-filter-confidence" class="projects-filter-select-native">
|
||||
<option value="" data-i18n="projects.all">全部</option>
|
||||
<option value="confirmed" data-i18n="projects.confidenceConfirmed">已确认</option>
|
||||
<option value="tentative" data-i18n="projects.confidenceTentative">待确认</option>
|
||||
@@ -1848,7 +1848,7 @@
|
||||
<div class="projects-fact-toolbar-filters projects-graph-toolbar-row">
|
||||
<label class="projects-fact-filter-field">
|
||||
<span class="projects-fact-filter-label" data-i18n="projects.graphView">视图</span>
|
||||
<select id="project-graph-view" onchange="loadProjectFactGraph()">
|
||||
<select id="project-graph-view" class="projects-filter-select-native">
|
||||
<option value="path" data-i18n="projects.graphViewPath">攻击路径</option>
|
||||
<option value="full" data-i18n="projects.graphViewFull">完整关系</option>
|
||||
</select>
|
||||
@@ -1961,7 +1961,7 @@
|
||||
</label>
|
||||
<label class="projects-fact-filter-field">
|
||||
<span class="projects-fact-filter-label" data-i18n="projects.severity">严重度</span>
|
||||
<select id="project-vulns-filter-severity" onchange="loadProjectVulnerabilities()">
|
||||
<select id="project-vulns-filter-severity" class="projects-filter-select-native">
|
||||
<option value="" data-i18n="projects.all">全部</option>
|
||||
<option value="critical">critical</option>
|
||||
<option value="high">high</option>
|
||||
@@ -1972,7 +1972,7 @@
|
||||
</label>
|
||||
<label class="projects-fact-filter-field">
|
||||
<span class="projects-fact-filter-label" data-i18n="projects.status">状态</span>
|
||||
<select id="project-vulns-filter-status" onchange="loadProjectVulnerabilities()">
|
||||
<select id="project-vulns-filter-status" class="projects-filter-select-native">
|
||||
<option value="" data-i18n="projects.all">全部</option>
|
||||
<option value="open" data-i18n="vulnerabilityPage.statusOpen">待处理</option>
|
||||
<option value="confirmed" data-i18n="vulnerabilityPage.statusConfirmed">已确认</option>
|
||||
@@ -2020,7 +2020,7 @@
|
||||
<div class="projects-form-field">
|
||||
<label for="project-edit-status" data-i18n="projects.status">状态</label>
|
||||
<div class="projects-status-select-wrap">
|
||||
<select id="project-edit-status" class="form-input projects-status-select">
|
||||
<select id="project-edit-status" class="form-input projects-status-select projects-filter-select-native">
|
||||
<option value="active" data-i18n="projects.statusActive">进行中</option>
|
||||
<option value="archived" data-i18n="projects.statusArchived">已归档</option>
|
||||
</select>
|
||||
@@ -2317,7 +2317,7 @@
|
||||
</label>
|
||||
<label>
|
||||
<span data-i18n="chatFilesPage.groupBy">分组</span>
|
||||
<select id="chat-files-group-by" class="form-control" onchange="chatFilesGroupByChange()">
|
||||
<select id="chat-files-group-by" class="form-control chat-files-filter-select-native">
|
||||
<option value="none" data-i18n="chatFilesPage.groupNone">不分组</option>
|
||||
<option value="date" data-i18n="chatFilesPage.groupByDate">按日期</option>
|
||||
<option value="conversation" data-i18n="chatFilesPage.groupByConversation">按会话</option>
|
||||
@@ -2356,7 +2356,7 @@
|
||||
<div class="batch-queues-filters tasks-filters batch-queues-filters--compact">
|
||||
<label>
|
||||
<span data-i18n="tasksPage.statusFilter">状态筛选</span>
|
||||
<select id="batch-queues-status-filter" onchange="filterBatchQueues()">
|
||||
<select id="batch-queues-status-filter" class="tasks-filter-select">
|
||||
<option value="all" data-i18n="knowledgePage.all">全部</option>
|
||||
<option value="pending" data-i18n="tasksPage.statusPending">待执行</option>
|
||||
<option value="running" data-i18n="dashboard.executing">执行中</option>
|
||||
@@ -2616,7 +2616,7 @@
|
||||
</div>
|
||||
<div class="form-group" id="workflow-prop-type-wrap">
|
||||
<label for="workflow-prop-type" data-i18n="workflows.propType">类型</label>
|
||||
<select id="workflow-prop-type" onchange="updateWorkflowSelectedProperty()">
|
||||
<select id="workflow-prop-type" class="workflow-form-select-native" onchange="updateWorkflowSelectedProperty()">
|
||||
<option value="start" data-i18n="workflows.nodes.start">开始</option>
|
||||
<option value="tool" data-i18n="workflows.nodes.tool">工具</option>
|
||||
<option value="agent" data-i18n="workflows.nodes.agent">Agent</option>
|
||||
@@ -5065,14 +5065,14 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="role-workflow-id" data-i18n="roleModal.bindWorkflow">绑定图编排流程</label>
|
||||
<select id="role-workflow-id">
|
||||
<select id="role-workflow-id" class="role-form-select-native">
|
||||
<option value="" data-i18n="roleModal.noWorkflowBind">不绑定流程</option>
|
||||
</select>
|
||||
<small class="form-hint" data-i18n="roleModal.bindWorkflowHint">选中流程后,对话页使用该角色会自动触发绑定图;流程字段由图定义 JSON 自由配置。</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="role-workflow-policy" data-i18n="roleModal.workflowPolicy">流程触发策略</label>
|
||||
<select id="role-workflow-policy">
|
||||
<select id="role-workflow-policy" class="role-form-select-native">
|
||||
<option value="auto" data-i18n="roleModal.workflowPolicyAuto">自动触发</option>
|
||||
<option value="off" data-i18n="roleModal.workflowPolicyOff">关闭</option>
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user