mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-10-30 01:46:36 +01:00
Merge pull request #370 from GQingL/main
Enhance RBAC UI with scrolling, spacing, and layout fixes
This commit is contained in:
15 files changed
+212
-27
No files matched your search
@@ -10604,6 +10604,43 @@ html[data-theme="dark"] .robot-binding-service-hint-icon {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.pagination-custom-select {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
width: 76px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.pagination-custom-select .settings-custom-select-trigger {
|
||||
min-height: 34px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.pagination-custom-select .settings-custom-select-caret {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-right: 1.5px solid currentColor;
|
||||
border-bottom: 1.5px solid currentColor;
|
||||
font-size: 0;
|
||||
transform: translateY(-2px) rotate(45deg);
|
||||
}
|
||||
|
||||
.settings-custom-select.pagination-custom-select.open .settings-custom-select-caret {
|
||||
transform: translateY(2px) rotate(225deg);
|
||||
}
|
||||
|
||||
.sidebar-list-pagination .pagination-custom-select {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.sidebar-list-pagination .pagination-custom-select .settings-custom-select-trigger {
|
||||
min-height: 28px;
|
||||
padding: 4px 8px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.settings-custom-select-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
@@ -14008,6 +14045,10 @@ html[data-theme="dark"] .robot-binding-service-hint-icon {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(110px, 0.65fr) minmax(150px, 1fr) minmax(190px, 1.25fr);
|
||||
gap: 8px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
overscroll-behavior-x: contain;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.rbac-resource-filterbar :is(.form-select, .form-input),
|
||||
@@ -16117,6 +16158,8 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
|
||||
.external-mcp-actions {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
@@ -16124,9 +16167,12 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
|
||||
.external-mcp-stats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-left: auto;
|
||||
gap: 8px 20px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
margin-left: 0;
|
||||
padding: 10px 20px;
|
||||
background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--bg-tertiary) 100%);
|
||||
border: 1px solid var(--border-color);
|
||||
@@ -16228,21 +16274,24 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
|
||||
.external-mcp-item-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.external-mcp-item-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.external-mcp-item-info h4 {
|
||||
flex: 1 1 180px;
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
margin: 0;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
@@ -16269,6 +16318,7 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
}
|
||||
|
||||
.external-mcp-status {
|
||||
flex-shrink: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
@@ -16347,6 +16397,7 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
.external-mcp-item-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@@ -33734,6 +33785,14 @@ html[data-theme="dark"] .chat-files-toast.chat-toast--error {
|
||||
font-size: 0.75rem;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.sidebar-list-pagination .projects-filter-select-dropdown {
|
||||
top: auto;
|
||||
bottom: calc(100% + 4px);
|
||||
left: auto;
|
||||
min-width: 88px;
|
||||
}
|
||||
|
||||
.projects-fact-filter-field--search input {
|
||||
padding-left: 34px;
|
||||
background: #fff;
|
||||
@@ -42301,6 +42360,12 @@ html[data-theme="dark"] .workflow-toolbar #workflow-connect-btn[aria-pressed="tr
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.rbac-panel-users > .rbac-panel-head,
|
||||
.rbac-panel-users > .rbac-search {
|
||||
/* Keep the fixed controls intact when a long member list needs to shrink. */
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.rbac-panel-users .rbac-list {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
@@ -42694,7 +42759,7 @@ html[data-theme="dark"] .workflow-toolbar #workflow-connect-btn[aria-pressed="tr
|
||||
gap: 0;
|
||||
min-height: 0;
|
||||
max-height: none;
|
||||
padding: 0 12px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.rbac-assignments-list .rbac-assignment-row {
|
||||
@@ -42814,19 +42879,23 @@ html[data-theme="dark"] .workflow-toolbar #workflow-connect-btn[aria-pressed="tr
|
||||
}
|
||||
|
||||
.rbac-role-management {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
padding: 18px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.rbac-role-management-head {
|
||||
flex: 0 0 auto;
|
||||
align-items: flex-end;
|
||||
flex-wrap: wrap;
|
||||
row-gap: 12px;
|
||||
}
|
||||
|
||||
.rbac-role-management-head > div:first-child {
|
||||
flex: 1 1 320px;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@@ -42861,7 +42930,12 @@ html[data-theme="dark"] .workflow-toolbar #workflow-connect-btn[aria-pressed="tr
|
||||
}
|
||||
|
||||
.rbac-role-catalog {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr));
|
||||
align-content: start;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
|
||||
@@ -402,6 +402,7 @@ function renderAuditLogsPagination() {
|
||||
html += '<button type="button" class="btn-secondary" onclick="goAuditLogsPage(' + totalPages + ')"' + (disabledLast ? ' disabled' : '') + '>' + esc(lastPageLabel) + '</button>';
|
||||
html += '</div></div>';
|
||||
container.innerHTML = html;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(container);
|
||||
}
|
||||
|
||||
function goAuditLogsPage(p) {
|
||||
|
||||
@@ -3256,6 +3256,7 @@
|
||||
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
||||
if (total === 0) {
|
||||
paginationContainer.innerHTML = '';
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(paginationContainer);
|
||||
return;
|
||||
}
|
||||
const start = total === 0 ? 0 : (currentPage - 1) * pageSize + 1;
|
||||
@@ -3284,6 +3285,7 @@
|
||||
`;
|
||||
html += '</div>';
|
||||
paginationContainer.innerHTML = html;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(paginationContainer);
|
||||
if (typeof applyTranslations === 'function') applyTranslations(paginationContainer);
|
||||
};
|
||||
|
||||
@@ -4194,6 +4196,7 @@
|
||||
|
||||
if (total === 0) {
|
||||
paginationContainer.innerHTML = '';
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(paginationContainer);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4224,6 +4227,7 @@
|
||||
`;
|
||||
html += '</div>';
|
||||
paginationContainer.innerHTML = html;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(paginationContainer);
|
||||
if (typeof applyTranslations === 'function') applyTranslations(paginationContainer);
|
||||
};
|
||||
|
||||
|
||||
@@ -509,6 +509,7 @@ function renderChatFilesPagination() {
|
||||
if (groupMode === 'folder' || chatFilesTotal <= 0) {
|
||||
pager.hidden = true;
|
||||
pager.innerHTML = '';
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(pager);
|
||||
return;
|
||||
}
|
||||
const totalPages = chatFilesTotalPages();
|
||||
@@ -542,6 +543,7 @@ function renderChatFilesPagination() {
|
||||
<button type="button" class="btn-secondary" ${chatFilesPage >= totalPages ? 'disabled' : ''} onclick="changeChatFilesPage(${chatFilesPage + 1})">${escapeHtml(nextLabel)}</button>
|
||||
</div>`;
|
||||
pager.hidden = false;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(pager);
|
||||
}
|
||||
|
||||
function changeChatFilesPage(page) {
|
||||
|
||||
@@ -9923,6 +9923,7 @@ function renderConversationsPagination(visibleCount) {
|
||||
if (!total) {
|
||||
el.innerHTML = '';
|
||||
el.hidden = true;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(el);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9963,6 +9964,7 @@ function renderConversationsPagination(visibleCount) {
|
||||
</select>
|
||||
</label>
|
||||
</div>`;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(el);
|
||||
} finally {
|
||||
conversationsPaginationRenderLock = false;
|
||||
}
|
||||
|
||||
@@ -174,6 +174,7 @@ function renderHitlPagination(containerId, state, goPageFnName, pageSizeChangeFn
|
||||
html += '<button type="button" class="btn-secondary" onclick="' + esc(goPageFnName) + '(' + totalPages + ')"' + (disabledLast ? ' disabled' : '') + '>' + esc(lastPageLabel) + '</button>';
|
||||
html += '</div></div>';
|
||||
container.innerHTML = html;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(container);
|
||||
}
|
||||
|
||||
function hitlEffectiveEnabled(cfg) {
|
||||
|
||||
@@ -9322,6 +9322,7 @@ function renderMonitorPagination() {
|
||||
`;
|
||||
|
||||
container.appendChild(pagination);
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(pagination);
|
||||
|
||||
// 初始化每页显示数量选择器
|
||||
initializeMonitorPageSize();
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const vm = require('node:vm');
|
||||
|
||||
function setup() {
|
||||
const source = fs.readFileSync(path.join(__dirname, 'settings.js'), 'utf8');
|
||||
const context = vm.createContext({ window: { innerWidth: 800, innerHeight: 600 } });
|
||||
vm.runInContext(source.slice(0, source.indexOf('function getRobotStatus(')), context);
|
||||
vm.runInContext('globalThis.selects = settingsCustomSelects;', context);
|
||||
return context;
|
||||
}
|
||||
|
||||
function menuAt(rect) {
|
||||
return {
|
||||
wrapper: { classList: { contains: () => true } },
|
||||
trigger: { getBoundingClientRect: () => rect },
|
||||
menu: { style: {} },
|
||||
};
|
||||
}
|
||||
|
||||
test('a pagination menu near the viewport bottom opens above its trigger', () => {
|
||||
const context = setup();
|
||||
const reg = menuAt({ left: 700, top: 550, bottom: 584, width: 76 });
|
||||
context.positionSettingsCustomSelectMenu(reg);
|
||||
assert.equal(reg.menu.style.top, 'auto');
|
||||
assert.equal(reg.menu.style.bottom, '56px');
|
||||
assert.ok(parseInt(reg.menu.style.left) + parseInt(reg.menu.style.width) <= 788);
|
||||
});
|
||||
|
||||
test('a menu near the viewport top opens below instead', () => {
|
||||
const context = setup();
|
||||
const reg = menuAt({ left: 20, top: 20, bottom: 54, width: 76 });
|
||||
context.positionSettingsCustomSelectMenu(reg);
|
||||
assert.equal(reg.menu.style.top, '60px');
|
||||
assert.equal(reg.menu.style.bottom, 'auto');
|
||||
});
|
||||
|
||||
test('replacing pagination DOM removes its detached floating menu', () => {
|
||||
const context = setup();
|
||||
let removed = false;
|
||||
let synced = null;
|
||||
const stale = { isConnected: false };
|
||||
const current = { isConnected: true };
|
||||
const reg = {
|
||||
wrapper: { classList: { remove() {} }, appendChild(menu) { menu.parentNode = this; } },
|
||||
trigger: { setAttribute() {} },
|
||||
menu: { style: {}, classList: { remove() {} }, remove() { removed = true; } },
|
||||
};
|
||||
context.selects.set(stale, reg);
|
||||
context.selects.set(current, {});
|
||||
context.syncSettingsCustomSelect = select => { synced = select; };
|
||||
context.refreshSettingsCustomSelects();
|
||||
assert.equal(removed, true);
|
||||
assert.equal(context.selects.has(stale), false);
|
||||
assert.equal(context.selects.has(current), true);
|
||||
assert.equal(synced, current);
|
||||
});
|
||||
@@ -1135,6 +1135,7 @@ function renderProjectAssetsPagination() {
|
||||
<button type="button" class="btn-secondary" onclick="loadProjectAssets(${totalPages})" ${atLast ? 'disabled' : ''}>${escapeHtml(tpFmt('skillsPage.lastPage', '尾页'))}</button>
|
||||
</div>
|
||||
</div>`;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(root);
|
||||
}
|
||||
|
||||
function changeProjectAssetsPageSize(value) {
|
||||
|
||||
@@ -1032,6 +1032,7 @@ function renderRoleToolsPagination() {
|
||||
`;
|
||||
|
||||
toolsList.appendChild(pagination);
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(pagination);
|
||||
}
|
||||
|
||||
function syncRoleToolsFilterButtons() {
|
||||
|
||||
@@ -172,7 +172,15 @@ function syncSettingsCustomSelect(select) {
|
||||
}
|
||||
|
||||
function refreshSettingsCustomSelects() {
|
||||
settingsCustomSelects.forEach((_reg, select) => syncSettingsCustomSelect(select));
|
||||
settingsCustomSelects.forEach((reg, select) => {
|
||||
if (!select.isConnected) {
|
||||
closeSettingsCustomSelect(select);
|
||||
reg.menu.remove();
|
||||
settingsCustomSelects.delete(select);
|
||||
return;
|
||||
}
|
||||
syncSettingsCustomSelect(select);
|
||||
});
|
||||
}
|
||||
|
||||
function enhanceSettingsSelect(select) {
|
||||
@@ -277,10 +285,7 @@ function enhanceSettingsSelect(select) {
|
||||
syncSettingsCustomSelect(select);
|
||||
}
|
||||
|
||||
function initSettingsCustomSelects(root) {
|
||||
const scope = root || document.getElementById('page-settings');
|
||||
if (!scope) return;
|
||||
scope.querySelectorAll('select').forEach(enhanceSettingsSelect);
|
||||
function bindSettingsCustomSelectEvents() {
|
||||
if (!settingsCustomSelectsDocBound) {
|
||||
document.addEventListener('click', closeAllSettingsCustomSelects);
|
||||
document.addEventListener('keydown', (event) => {
|
||||
@@ -288,8 +293,35 @@ function initSettingsCustomSelects(root) {
|
||||
});
|
||||
document.addEventListener('scroll', repositionOpenSettingsCustomSelects, true);
|
||||
window.addEventListener('resize', repositionOpenSettingsCustomSelects);
|
||||
window.addEventListener('hashchange', closeAllSettingsCustomSelects);
|
||||
settingsCustomSelectsDocBound = true;
|
||||
}
|
||||
}
|
||||
|
||||
function initSettingsCustomSelects(root) {
|
||||
const scope = root || document.getElementById('page-settings');
|
||||
if (!scope) return;
|
||||
scope.querySelectorAll('select').forEach(enhanceSettingsSelect);
|
||||
bindSettingsCustomSelectEvents();
|
||||
refreshSettingsCustomSelects();
|
||||
}
|
||||
|
||||
// Pagination menus use the floating select so clipped panels cannot hide options.
|
||||
function initPaginationSelects(root) {
|
||||
if (!root) return;
|
||||
root.querySelectorAll('.pagination-page-size select').forEach(select => {
|
||||
if (select.dataset.projectsCustomSelect === '1') return;
|
||||
enhanceSettingsSelect(select);
|
||||
const reg = settingsCustomSelects.get(select);
|
||||
if (!reg) return;
|
||||
reg.wrapper.classList.add('pagination-custom-select');
|
||||
const label = select.labels?.[0] || select.closest('.pagination-page-size');
|
||||
const labelText = label && Array.from(label.childNodes)
|
||||
.filter(node => node.nodeType === 3).map(node => node.textContent).join(' ').trim();
|
||||
const accessibleName = select.getAttribute('aria-label') || labelText;
|
||||
if (accessibleName) reg.trigger.setAttribute('aria-label', accessibleName);
|
||||
});
|
||||
bindSettingsCustomSelectEvents();
|
||||
refreshSettingsCustomSelects();
|
||||
}
|
||||
|
||||
@@ -1675,6 +1707,7 @@ function renderToolsPagination() {
|
||||
|
||||
// 如果只有一页或没有数据,不显示分页
|
||||
if (toolsPagination.totalPages <= 1) {
|
||||
initPaginationSelects(toolsList);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1716,6 +1749,7 @@ function renderToolsPagination() {
|
||||
`;
|
||||
|
||||
toolsList.appendChild(pagination);
|
||||
initPaginationSelects(pagination);
|
||||
}
|
||||
|
||||
// 处理工具checkbox状态变化
|
||||
|
||||
@@ -231,6 +231,7 @@ function renderSkillsPagination() {
|
||||
// 即使只有一页也显示分页信息(参考MCP样式)
|
||||
if (total === 0) {
|
||||
paginationContainer.innerHTML = '';
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(paginationContainer);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -277,6 +278,7 @@ function renderSkillsPagination() {
|
||||
paginationHTML += '</div>';
|
||||
|
||||
paginationContainer.innerHTML = paginationHTML;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(paginationContainer);
|
||||
|
||||
// 确保分页组件与列表内容区域对齐(不包括滚动条)
|
||||
function alignPaginationWidth() {
|
||||
|
||||
@@ -1687,6 +1687,7 @@ function renderBatchQueuesPagination() {
|
||||
// 即使只有一页也显示分页信息(与 MCP 监控一致)
|
||||
if (total === 0) {
|
||||
paginationContainer.innerHTML = '';
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(paginationContainer);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1726,6 +1727,7 @@ function renderBatchQueuesPagination() {
|
||||
paginationHTML += '</div>';
|
||||
|
||||
paginationContainer.innerHTML = paginationHTML;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(paginationContainer);
|
||||
}
|
||||
|
||||
// 跳转到指定页面
|
||||
|
||||
@@ -1522,6 +1522,7 @@ function renderVulnerabilityPagination() {
|
||||
paginationHTML += '</div>';
|
||||
|
||||
paginationContainer.innerHTML = paginationHTML;
|
||||
if (typeof initPaginationSelects === 'function') initPaginationSelects(paginationContainer);
|
||||
if (typeof window.applyTranslations === 'function') {
|
||||
window.applyTranslations(paginationContainer);
|
||||
}
|
||||
|
||||
+13
-13
@@ -39,7 +39,7 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet" href="/static/css/style.css?v=20261027-settings-sidebar-scroll">
|
||||
<link rel="stylesheet" href="/static/css/style.css?v=20261027-pagination-custom-select">
|
||||
<link rel="stylesheet" href="/static/css/tool-guard.css?v=20260907-7">
|
||||
<link rel="stylesheet" href="/static/css/chat-plan-progress.css?v=20260813-4">
|
||||
<link rel="stylesheet" href="/static/css/c2.css">
|
||||
@@ -7024,35 +7024,35 @@
|
||||
<script src="/static/js/agents.js"></script>
|
||||
<script src="/static/js/dashboard.js?v=20261011-token-settings-cache-only"></script>
|
||||
<script src="/static/js/chat-scroll.js?v=20260815-1"></script>
|
||||
<script src="/static/js/monitor.js?v=20261011-token-usage"></script>
|
||||
<script src="/static/js/monitor.js?v=20261011-token-usage-pagination-20261027"></script>
|
||||
<script src="/static/js/attack-chain-context.js?v=20261012-summary-2"></script>
|
||||
<script src="/static/js/chat.js?v=20261016-context-memory-token-usage"></script>
|
||||
<script src="/static/js/chat.js?v=20261016-context-memory-token-usage-pagination-20261027"></script>
|
||||
<script src="/static/js/chat-plan-progress.js?v=20260815-1"></script>
|
||||
<script src="/static/js/hitl.js?v=20260819-1"></script>
|
||||
<script src="/static/js/hitl.js?v=20260819-1-pagination-20261027"></script>
|
||||
<script src="/static/js/tool-guard.js?v=20261010-conflict"></script>
|
||||
<script src="/static/js/token-usage.js?v=20261012-token-analytics"></script>
|
||||
<script src="/static/js/settings.js?v=20261011-token-settings"></script>
|
||||
<script src="/static/js/settings.js?v=20261011-token-settings-pagination-20261027"></script>
|
||||
<script src="/static/js/audit-datetime-picker.js"></script>
|
||||
<script src="/static/js/audit.js"></script>
|
||||
<script src="/static/js/audit.js?v=20261027-pagination-custom-select"></script>
|
||||
<script src="/static/js/storage.js"></script>
|
||||
<script src="/static/js/wechat-robot.js"></script>
|
||||
<script src="/static/vendor/xterm.js"></script>
|
||||
<script src="/static/vendor/xterm-addon-fit.js"></script>
|
||||
<script src="/static/js/terminal.js"></script>
|
||||
<script src="/static/js/knowledge.js"></script>
|
||||
<script src="/static/js/skills.js"></script>
|
||||
<script src="/static/js/skills.js?v=20261027-pagination-custom-select"></script>
|
||||
<script src="/static/js/fact-graph.js"></script>
|
||||
<script src="/static/js/projects.js?v=20260819-1"></script>
|
||||
<script src="/static/js/vulnerability.js?v=20261010-retest-2"></script>
|
||||
<script src="/static/js/projects.js?v=20260819-1-pagination-20261027"></script>
|
||||
<script src="/static/js/vulnerability.js?v=20261010-retest-2-pagination-20261027"></script>
|
||||
<script src="/static/js/webshell.js?v=20261011-token-usage"></script>
|
||||
<script src="/static/js/chat-files.js"></script>
|
||||
<script src="/static/js/tasks.js"></script>
|
||||
<script src="/static/js/chat-files.js?v=20261027-pagination-custom-select"></script>
|
||||
<script src="/static/js/tasks.js?v=20261027-pagination-custom-select"></script>
|
||||
<script src="/static/js/workflow-package-client.js"></script>
|
||||
<script src="/static/js/workflows.js"></script>
|
||||
<script src="/static/js/update.js?v={{.Version}}"></script>
|
||||
<script src="/static/js/roles.js"></script>
|
||||
<script src="/static/js/roles.js?v=20261027-pagination-custom-select"></script>
|
||||
<script src="/static/js/rbac.js"></script>
|
||||
<script src="/static/js/c2.js"></script>
|
||||
<script src="/static/js/c2.js?v=20261027-pagination-custom-select"></script>
|
||||
<script src="/static/js/rbac-guards.js?v=20260907-1"></script>
|
||||
<!-- 移动端交互层:必须最后加载,它包装 window.switchPage 并注入移动端 DOM -->
|
||||
<script src="/static/js/mobile-ui.js?v=20261006-9"></script>
|
||||
|
||||
Reference in new issue
Block a user