mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-18 17:07:21 +02:00
Add files via upload
This commit is contained in:
+83
-12
@@ -84,6 +84,7 @@ function initChatFilesPage() {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
setupChatFilesDragDrop();
|
||||
loadChatFilesPage();
|
||||
}
|
||||
|
||||
@@ -1226,21 +1227,31 @@ function chatFilesUploadToFolderClick(ev, btn) {
|
||||
if (inp) inp.click();
|
||||
}
|
||||
|
||||
async function onChatFilesUploadPick(ev) {
|
||||
const input = ev.target;
|
||||
const file = input && input.files && input.files[0];
|
||||
if (!file) return;
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
function chatFilesResolveUploadTarget() {
|
||||
const pendingDir = chatFilesPendingUploadDir;
|
||||
chatFilesPendingUploadDir = '';
|
||||
if (pendingDir) {
|
||||
form.append('relativeDir', pendingDir);
|
||||
} else {
|
||||
const conv = document.getElementById('chat-files-filter-conv');
|
||||
if (conv && conv.value.trim()) {
|
||||
form.append('conversationId', conv.value.trim());
|
||||
}
|
||||
return { relativeDir: pendingDir };
|
||||
}
|
||||
if (chatFilesGetGroupByMode() === 'folder') {
|
||||
const dir = chatFilesBrowsePath.join('/');
|
||||
return dir ? { relativeDir: dir } : {};
|
||||
}
|
||||
const conv = document.getElementById('chat-files-filter-conv');
|
||||
if (conv && conv.value.trim()) {
|
||||
return { conversationId: conv.value.trim() };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
async function chatFilesUploadFile(file, target) {
|
||||
if (!file || chatFilesXHRUploadBusy) return false;
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
if (target && target.relativeDir) {
|
||||
form.append('relativeDir', target.relativeDir);
|
||||
} else if (target && target.conversationId) {
|
||||
form.append('conversationId', target.conversationId);
|
||||
}
|
||||
chatFilesSetUploadBusy(true);
|
||||
chatFilesSetUploadProgressUI(true, 0, file.name);
|
||||
@@ -1265,15 +1276,75 @@ async function onChatFilesUploadPick(ev) {
|
||||
: '上传成功。在列表中点击「复制路径」即可粘贴到对话中引用。';
|
||||
chatFilesShowToast(msg);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
alert((e && e.message) ? e.message : String(e));
|
||||
return false;
|
||||
} finally {
|
||||
chatFilesSetUploadBusy(false);
|
||||
chatFilesSetUploadProgressUI(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function chatFilesUploadFiles(fileList) {
|
||||
if (!fileList || !fileList.length || chatFilesXHRUploadBusy) return;
|
||||
const files = Array.from(fileList).filter(function (f) {
|
||||
return f && (f.name || f.size > 0);
|
||||
});
|
||||
if (!files.length) return;
|
||||
const target = chatFilesResolveUploadTarget();
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const ok = await chatFilesUploadFile(files[i], target);
|
||||
if (!ok) break;
|
||||
}
|
||||
}
|
||||
|
||||
async function onChatFilesUploadPick(ev) {
|
||||
const input = ev.target;
|
||||
const files = input && input.files;
|
||||
if (!files || !files.length) return;
|
||||
try {
|
||||
await chatFilesUploadFiles(files);
|
||||
} finally {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
let chatFilesDragDropBound = false;
|
||||
|
||||
function setupChatFilesDragDrop() {
|
||||
if (chatFilesDragDropBound) return;
|
||||
const wrap = document.getElementById('chat-files-list-wrap');
|
||||
if (!wrap) return;
|
||||
chatFilesDragDropBound = true;
|
||||
|
||||
wrap.addEventListener('dragover', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (chatFilesXHRUploadBusy) return;
|
||||
this.classList.add('drag-over');
|
||||
});
|
||||
wrap.addEventListener('dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!this.contains(e.relatedTarget)) {
|
||||
this.classList.remove('drag-over');
|
||||
}
|
||||
});
|
||||
wrap.addEventListener('drop', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.classList.remove('drag-over');
|
||||
if (chatFilesXHRUploadBusy) return;
|
||||
const files = e.dataTransfer && e.dataTransfer.files;
|
||||
if (files && files.length) {
|
||||
chatFilesUploadFiles(files).catch(function (err) {
|
||||
if (err) alert((err && err.message) ? err.message : String(err));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 语言切换后重新渲染列表:表头与「更多」菜单由 JS 拼接,无 data-i18n,需用当前语言的 t() 再生成一遍
|
||||
document.addEventListener('languagechange', function () {
|
||||
if (typeof window.currentPage !== 'function') return;
|
||||
|
||||
+30
-19
@@ -137,9 +137,12 @@ function normalizeHitlMode(mode) {
|
||||
}
|
||||
|
||||
function defaultHitlConfig() {
|
||||
const serverReviewer = (typeof window !== 'undefined' && window.csaiHitlDefaultReviewer)
|
||||
? window.csaiHitlDefaultReviewer
|
||||
: 'human';
|
||||
return {
|
||||
mode: HITL_MODE_OFF,
|
||||
reviewer: 'human',
|
||||
reviewer: normalizeHitlReviewer(serverReviewer),
|
||||
sensitiveTools: '',
|
||||
updatedAt: ''
|
||||
};
|
||||
@@ -315,16 +318,18 @@ async function onHitlReviewerChanged(reviewer) {
|
||||
const cfg = readHitlConfigFromForm();
|
||||
const cid = typeof currentConversationId === 'string' ? currentConversationId.trim() : '';
|
||||
saveHitlConfigForConversation(cid, cfg, { syncGlobalLast: true });
|
||||
if (cid && typeof window.saveHitlConversationConfig === 'function') {
|
||||
try {
|
||||
try {
|
||||
if (cid && typeof window.saveHitlConversationConfig === 'function') {
|
||||
await window.saveHitlConversationConfig(cid, cfg);
|
||||
const ok = typeof window.t === 'function' ? window.t('hitl.pageReviewerSaved') : '审批方已保存。';
|
||||
showChatToast(ok, 'success');
|
||||
} catch (e) {
|
||||
console.warn('onHitlReviewerChanged', e);
|
||||
const prefix = typeof window.t === 'function' ? window.t('chat.hitlApplyFail') : '同步到服务器失败';
|
||||
showChatToast(prefix, 'error');
|
||||
} else if (typeof window.putHitlDefaultReviewer === 'function') {
|
||||
await window.putHitlDefaultReviewer(cfg.reviewer);
|
||||
}
|
||||
const ok = typeof window.t === 'function' ? window.t('hitl.pageReviewerSaved') : '审批方已保存。';
|
||||
showChatToast(ok, 'success');
|
||||
} catch (e) {
|
||||
console.warn('onHitlReviewerChanged', e);
|
||||
const prefix = typeof window.t === 'function' ? window.t('chat.hitlApplyFail') : '同步到服务器失败';
|
||||
showChatToast(prefix, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,6 +512,7 @@ function chatAgentModeNormalizeStored(stored, cfg) {
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.csaiHitlGlobalToolWhitelist = window.csaiHitlGlobalToolWhitelist || [];
|
||||
window.csaiHitlDefaultReviewer = window.csaiHitlDefaultReviewer || 'human';
|
||||
window.csaiChatAgentMode = {
|
||||
EINO_MODES: CHAT_AGENT_EINO_MODES,
|
||||
EINO_SINGLE: CHAT_AGENT_MODE_EINO_SINGLE,
|
||||
@@ -518,6 +524,7 @@ if (typeof window !== 'undefined') {
|
||||
window.applyHitlSidebarConfig = applyHitlSidebarConfig;
|
||||
window.readHitlConfigFromForm = readHitlConfigFromForm;
|
||||
window.applyHitlConfigToUI = applyHitlConfigToUI;
|
||||
window.refreshHitlConfigByCurrentConversation = refreshHitlConfigByCurrentConversation;
|
||||
window.saveHitlConfigForConversation = saveHitlConfigForConversation;
|
||||
window.getHitlConfigForConversation = getHitlConfigForConversation;
|
||||
bindHitlSidebarModeListener();
|
||||
@@ -2020,6 +2027,19 @@ function refreshSystemReadyMessageBubbles() {
|
||||
});
|
||||
}
|
||||
|
||||
function createMessageAvatar(role) {
|
||||
const avatar = document.createElement('div');
|
||||
avatar.className = 'message-avatar';
|
||||
if (role === 'user') {
|
||||
avatar.innerHTML = '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><circle cx="12" cy="7" r="4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
||||
} else if (role === 'assistant') {
|
||||
avatar.innerHTML = '<img src="/static/logo.png" alt="" class="message-avatar-img">';
|
||||
} else {
|
||||
avatar.textContent = 'S';
|
||||
}
|
||||
return avatar;
|
||||
}
|
||||
|
||||
// 添加消息(options.systemReadyMessage 为 true 时,语言切换会刷新该条文案)
|
||||
function addMessage(role, content, mcpExecutionIds = null, progressId = null, createdAt = null, options = null) {
|
||||
const messagesDiv = document.getElementById('chat-messages');
|
||||
@@ -2030,16 +2050,7 @@ function addMessage(role, content, mcpExecutionIds = null, progressId = null, cr
|
||||
messageDiv.className = 'message ' + role;
|
||||
|
||||
// 创建头像
|
||||
const avatar = document.createElement('div');
|
||||
avatar.className = 'message-avatar';
|
||||
if (role === 'user') {
|
||||
avatar.textContent = 'U';
|
||||
} else if (role === 'assistant') {
|
||||
avatar.textContent = 'A';
|
||||
} else {
|
||||
avatar.textContent = 'S';
|
||||
}
|
||||
messageDiv.appendChild(avatar);
|
||||
messageDiv.appendChild(createMessageAvatar(role));
|
||||
|
||||
// 创建消息内容容器
|
||||
const contentWrapper = document.createElement('div');
|
||||
|
||||
@@ -231,10 +231,66 @@ async function fetchHitlConversationConfig(conversationId) {
|
||||
if (!data || !data.hitl) return null;
|
||||
return {
|
||||
hitl: data.hitl,
|
||||
defaultReviewer: hitlReviewerNormalize(data.defaultReviewer || 'human'),
|
||||
hitlGlobalToolWhitelist: Array.isArray(data.hitlGlobalToolWhitelist) ? data.hitlGlobalToolWhitelist : []
|
||||
};
|
||||
}
|
||||
|
||||
function applyHitlDefaultReviewerFromServer(reviewer) {
|
||||
const v = hitlReviewerNormalize(reviewer);
|
||||
if (typeof window !== 'undefined') {
|
||||
window.csaiHitlDefaultReviewer = v;
|
||||
}
|
||||
if (typeof window.saveHitlLastGlobalConfig === 'function' && typeof window.getHitlLastGlobalConfig === 'function') {
|
||||
const gl = window.getHitlLastGlobalConfig();
|
||||
const base = gl && typeof gl === 'object'
|
||||
? gl
|
||||
: { mode: 'off', sensitiveTools: '', updatedAt: '' };
|
||||
window.saveHitlLastGlobalConfig(Object.assign({}, base, {
|
||||
reviewer: v,
|
||||
updatedAt: new Date().toISOString()
|
||||
}));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
async function fetchHitlDefaultReviewer() {
|
||||
const resp = await hitlApiFetch('/api/hitl/default-reviewer', { credentials: 'same-origin' });
|
||||
if (!resp.ok) {
|
||||
return applyHitlDefaultReviewerFromServer('human');
|
||||
}
|
||||
const data = await resp.json();
|
||||
return applyHitlDefaultReviewerFromServer(data && data.defaultReviewer);
|
||||
}
|
||||
|
||||
async function putHitlDefaultReviewer(reviewer) {
|
||||
const normalized = hitlReviewerNormalize(reviewer);
|
||||
const resp = await hitlApiFetch('/api/hitl/default-reviewer', {
|
||||
method: 'PUT',
|
||||
credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ reviewer: normalized })
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const msg = await readHitlApiError(resp);
|
||||
throw new Error(msg || ('HTTP ' + resp.status));
|
||||
}
|
||||
const data = await resp.json();
|
||||
return applyHitlDefaultReviewerFromServer(data && data.defaultReviewer);
|
||||
}
|
||||
|
||||
async function initHitlDefaultReviewerFromServer() {
|
||||
try {
|
||||
await fetchHitlDefaultReviewer();
|
||||
if (!getCurrentConversationIdForHitl() && typeof window.refreshHitlConfigByCurrentConversation === 'function') {
|
||||
window.refreshHitlConfigByCurrentConversation();
|
||||
}
|
||||
refreshHitlPageReviewerBar();
|
||||
} catch (e) {
|
||||
console.warn('initHitlDefaultReviewerFromServer', e);
|
||||
}
|
||||
}
|
||||
|
||||
/** 无会话时:将免审批工具合并进服务端 config.yaml,返回更新后的全局白名单数组 */
|
||||
async function mergeHitlGlobalToolWhitelist(sensitiveTools) {
|
||||
const list = Array.isArray(sensitiveTools) ? sensitiveTools : [];
|
||||
@@ -462,6 +518,9 @@ async function syncHitlConfigFromServer(conversationId) {
|
||||
const pack = await fetchHitlConversationConfig(conversationId);
|
||||
if (!pack || !pack.hitl) return;
|
||||
const cfg = pack.hitl;
|
||||
if (pack.defaultReviewer) {
|
||||
applyHitlDefaultReviewerFromServer(pack.defaultReviewer);
|
||||
}
|
||||
const globalWL = pack.hitlGlobalToolWhitelist || [];
|
||||
if (typeof window !== 'undefined') {
|
||||
window.csaiHitlGlobalToolWhitelist = globalWL;
|
||||
@@ -1460,6 +1519,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
if (typeof window.bindHitlReviewerToggleListeners === 'function') {
|
||||
window.bindHitlReviewerToggleListeners();
|
||||
}
|
||||
initHitlDefaultReviewerFromServer();
|
||||
setTimeout(reconcileHitlUiState, 0);
|
||||
});
|
||||
|
||||
@@ -1478,3 +1538,5 @@ window.mergeHitlGlobalToolWhitelist = mergeHitlGlobalToolWhitelist;
|
||||
|
||||
// 由 chat.js 在 loadConversation 内 await 调用;挂到 window 供其它入口显式触发
|
||||
window.syncHitlConfigFromServer = syncHitlConfigFromServer;
|
||||
window.fetchHitlDefaultReviewer = fetchHitlDefaultReviewer;
|
||||
window.putHitlDefaultReviewer = putHitlDefaultReviewer;
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
if (el.classList.contains('info-collect-cell-modal')) {
|
||||
return 'flex';
|
||||
}
|
||||
if (el.classList.contains('chat-files-form-modal')) {
|
||||
return 'flex';
|
||||
}
|
||||
if (FLEX_MODAL_IDS.has(el.id)) {
|
||||
return 'flex';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user