Files
IC-Coder-Plugin/src/views/docsetDialog.ts
Roe-xin 1207d2b91a feat:实现携带路径发送信息的优化
- 将路径通过doc包裹起来便于后端读取
2026-03-20 11:45:01 +08:00

572 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 文档集对话框组件
* 功能:添加文档集的对话框
*/
export function getDocsetDialogContent(): string {
return `
<div class="docset-dialog" id="docsetDialog">
<div class="docset-dialog-overlay" onclick="closeDocsetDialog()"></div>
<div class="docset-dialog-content">
<div class="docset-dialog-header">
<h3>添加文档集</h3>
<button onclick="closeDocsetDialog()">×</button>
</div>
<div class="docset-dialog-body">
<div class="docset-form-group">
<label>名称</label>
<input type="text" id="docsetName" placeholder="输入文档集名称" />
</div>
<div class="docset-form-group">
<label>文件</label>
<div class="docset-hint">支持 .md/.txt/.v/.sv/.pdf单个文件最大 10 MB文档集最大 50 MB最多 1000 个文件</div>
<button class="docset-add-file-btn" id="addFileBtn" onclick="addFileToDocset()">
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M469.333333 469.333333V170.666667h85.333334v298.666666h298.666666v85.333334h-298.666666v298.666666h-85.333334v-298.666666H170.666667v-85.333334h298.666666z" fill="currentColor"/>
</svg>
添加文件
</button>
<div id="docsetFilesDisplay" style="display: none; margin-top: 8px;">
<div id="docsetFilesList" style="max-height: 200px; overflow-y: auto; border: 1px solid var(--vscode-input-border); border-radius: 4px; padding: 8px;"></div>
<div id="docsetFilesSummary" style="margin-top: 8px; font-size: 12px; color: var(--vscode-descriptionForeground);"></div>
</div>
</div>
</div>
<div class="docset-dialog-footer">
<button class="docset-btn-cancel" onclick="closeDocsetDialog()">取消</button>
<button class="docset-btn-confirm" onclick="confirmDocset()">确定</button>
</div>
</div>
</div>
<div class="delete-confirm-dialog" id="deleteConfirmDialog">
<div class="delete-confirm-content">
<div class="delete-confirm-title">确认删除</div>
<div class="delete-confirm-message" id="deleteConfirmMessage"></div>
<div class="delete-confirm-actions">
<button class="docset-btn-cancel" onclick="closeDeleteConfirm()">取消</button>
<button class="docset-btn-confirm" onclick="confirmDelete()">确定</button>
</div>
</div>
</div>
<div class="rename-dialog" id="renameDialog">
<div class="rename-content">
<div class="rename-title">修改名称</div>
<input type="text" id="renameInput" class="rename-input" placeholder="输入新名称" />
<div class="rename-actions">
<button class="docset-btn-cancel" onclick="closeRenameDialog()">取消</button>
<button class="docset-btn-confirm" onclick="confirmRename()">确定</button>
</div>
</div>
</div>
`;
}
export function getDocsetDialogStyles(): string {
return `
.docset-dialog {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 10000;
}
.docset-dialog.active {
display: flex;
align-items: center;
justify-content: center;
}
.docset-dialog-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
}
.docset-dialog-content {
position: relative;
width: 90%;
max-width: 500px;
background: var(--vscode-editor-background);
border: 1px solid var(--vscode-panel-border);
border-radius: 8px;
display: flex;
flex-direction: column;
max-height: 80vh;
}
.docset-dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
border-bottom: 1px solid var(--vscode-panel-border);
}
.docset-dialog-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
}
.docset-dialog-header button {
width: 32px;
height: 32px;
background: transparent;
border: none;
font-size: 24px;
cursor: pointer;
color: var(--vscode-foreground);
border-radius: 4px;
}
.docset-dialog-header button:hover {
background: var(--vscode-toolbar-hoverBackground);
}
.docset-dialog-body {
padding: 20px;
overflow-y: auto;
}
.docset-form-group {
margin-bottom: 20px;
}
.docset-form-group label {
display: block;
margin-bottom: 8px;
font-size: 13px;
font-weight: 500;
}
.docset-hint {
font-size: 11px;
font-weight: 400;
color: var(--vscode-descriptionForeground);
margin-bottom: 8px;
}
.docset-form-group input {
width: 100%;
padding: 8px 12px;
background: var(--vscode-input-background);
border: 1px solid var(--vscode-input-border);
border-radius: 4px;
color: var(--vscode-input-foreground);
font-size: 13px;
box-sizing: border-box;
}
.docset-add-file-btn {
display: flex;
align-items: center;
gap: 4px;
padding: 6px 12px;
background: transparent;
color: var(--vscode-textLink-foreground);
border: 1px solid var(--vscode-textLink-foreground);
border-radius: 4px;
cursor: pointer;
font-size: 12px;
}
.docset-add-file-btn:hover {
background: var(--vscode-toolbar-hoverBackground);
}
.docset-add-file-btn svg {
width: 14px;
height: 14px;
}
.docset-dialog-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
padding: 16px 20px;
border-top: 1px solid var(--vscode-panel-border);
}
.docset-dialog-footer button {
padding: 6px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
.docset-btn-cancel {
background: var(--vscode-button-secondaryBackground);
color: var(--vscode-button-secondaryForeground);
}
.docset-btn-cancel:hover {
background: var(--vscode-button-secondaryHoverBackground);
}
.docset-btn-confirm {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
}
.docset-btn-confirm:hover {
background: var(--vscode-button-hoverBackground);
}
.docset-delete-btn, .docset-change-btn {
position: relative;
background: transparent;
border: none;
cursor: pointer;
padding: 4px;
color: var(--vscode-foreground);
opacity: 0.6;
}
.docset-delete-btn:hover, .docset-change-btn:hover {
opacity: 1;
}
.docset-delete-btn:hover::after, .docset-change-btn:hover::after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: var(--vscode-editorHoverWidget-background);
color: var(--vscode-editorHoverWidget-foreground);
border: 1px solid var(--vscode-editorHoverWidget-border);
padding: 4px 8px;
border-radius: 3px;
font-size: 12px;
white-space: nowrap;
margin-bottom: 4px;
z-index: 1000;
}
.delete-confirm-dialog {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 10000;
align-items: center;
justify-content: center;
}
.delete-confirm-dialog.active {
display: flex;
}
.delete-confirm-content {
background: var(--vscode-editor-background);
border: 1px solid var(--vscode-panel-border);
border-radius: 6px;
padding: 20px;
min-width: 300px;
max-width: 400px;
}
.delete-confirm-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 12px;
}
.delete-confirm-message {
font-size: 13px;
color: var(--vscode-descriptionForeground);
margin-bottom: 16px;
}
.delete-confirm-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.delete-confirm-actions button {
padding: 6px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
.rename-dialog {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 10000;
align-items: center;
justify-content: center;
}
.rename-dialog.active {
display: flex;
}
.rename-content {
background: var(--vscode-editor-background);
border: 1px solid var(--vscode-panel-border);
border-radius: 6px;
padding: 20px;
min-width: 300px;
max-width: 400px;
}
.rename-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 12px;
}
.rename-input {
width: 100%;
padding: 8px 12px;
background: var(--vscode-input-background);
border: 1px solid var(--vscode-input-border);
border-radius: 4px;
color: var(--vscode-input-foreground);
font-size: 13px;
box-sizing: border-box;
margin-bottom: 16px;
}
.rename-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.rename-actions button {
padding: 6px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
`;
}
export function getDocsetDialogScript(): string {
return `
let docsetFiles = [];
function openAddDocumentSetDialog() {
const dialog = document.getElementById('docsetDialog');
if (dialog) {
dialog.classList.add('active');
docsetFiles = [];
document.getElementById('docsetName').value = '';
document.getElementById('addFileBtn').style.display = 'flex';
document.getElementById('docsetFilesDisplay').style.display = 'none';
}
}
function closeDocsetDialog() {
const dialog = document.getElementById('docsetDialog');
if (dialog) {
dialog.classList.remove('active');
}
}
function addFileToDocset() {
vscode.postMessage({ command: 'selectFilesForDocset' });
}
function formatFileSize(bytes) {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
}
function updateDocsetDisplay() {
if (docsetFiles.length === 0) {
document.getElementById('addFileBtn').style.display = 'flex';
document.getElementById('docsetFilesDisplay').style.display = 'none';
return;
}
document.getElementById('addFileBtn').style.display = 'none';
document.getElementById('docsetFilesDisplay').style.display = 'block';
const listEl = document.getElementById('docsetFilesList');
const summaryEl = document.getElementById('docsetFilesSummary');
listEl.innerHTML = docsetFiles.map((file, index) => \`
<div style="display: flex; justify-content: space-between; align-items: center; font-size: 12px; padding: 4px 0; color: var(--vscode-foreground);">
<span>\${file.name || file.absolutePath}</span>
<button onclick="removeDocsetFile(\${index})" style="background: transparent; border: none; color: var(--vscode-foreground); cursor: pointer; padding: 0 4px; opacity: 0.7;">
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
<path d="M10 3h3v1h-1v9l-1 1H4l-1-1V4H2V3h3V2a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v1zM9 2H6v1h3V2zM4 13h7V4H4v9zm2-8H5v7h1V5zm1 0h1v7H7V5zm2 0h1v7H9V5z"/>
</svg>
</button>
</div>
\`).join('');
const totalSize = docsetFiles.reduce((sum, f) => sum + (f.size || 0), 0);
summaryEl.textContent = \`已选择 \${docsetFiles.length} 个文件,总大小 \${formatFileSize(totalSize)}\`;
}
function removeDocsetFile(index) {
docsetFiles.splice(index, 1);
updateDocsetDisplay();
}
function confirmDocset() {
const name = document.getElementById('docsetName').value.trim();
if (!name) {
alert('请输入文档集名称');
return;
}
if (docsetFiles.length === 0) {
alert('请添加至少一个文件');
return;
}
vscode.postMessage({
command: 'saveDocumentSet',
name: name,
documents: docsetFiles
});
closeDocsetDialog();
}
function renderDocumentSets(documentSets) {
const listEl = document.getElementById('contextDocsList');
if (!listEl) return;
if (!documentSets || documentSets.length === 0) {
listEl.innerHTML = '<div class="context-empty"><p>暂无文档集</p></div>';
return;
}
listEl.innerHTML = documentSets.map(ds => \`
<div class="docset-item">
<div class="docset-name">\${ds.name}</div>
<div class="docset-meta">更新于 \${new Date(ds.updatedAt).toLocaleString('zh-CN')}</div>
<button class="docset-change-btn" data-tooltip="修改名称" onclick="changeDocsetName('\${ds.id}', '\${ds.name}')">
<svg t="1773883957219" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7170" width="14" height="14">
<path d="M745.76 369.86l-451 537.48a18.693 18.693 0 0 1-8.46 5.74l-136.58 45.27c-13.24 4.39-26.46-6.71-24.43-20.5l20.86-142.36c0.5-3.44 1.95-6.67 4.19-9.33l451-537.48c6.65-7.93 18.47-8.96 26.4-2.31l115.71 97.1c7.92 6.64 8.96 18.46 2.31 26.39zM894.53 192.56l-65.9 78.53c-6.65 7.93-18.47 8.96-26.4 2.31l-115.71-97.1c-7.93-6.65-8.96-18.47-2.31-26.4l65.9-78.53c6.65-7.93 18.47-8.96 26.4-2.31l115.71 97.1c7.93 6.65 8.96 18.47 2.31 26.4z" fill="currentColor" p-id="7171"></path>
</svg>
</button>
<button class="docset-delete-btn" data-tooltip="删除" onclick="showDeleteConfirm('\${ds.id}', '\${ds.name}')">
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
<path d="M10 3h3v1h-1v9l-1 1H4l-1-1V4H2V3h3V2a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v1zM9 2H6v1h3V2zM4 13h7V4H4v9zm2-8H5v7h1V5zm1 0h1v7H7V5zm2 0h1v7H9V5z"/>
</svg>
</button>
</div>
\`).join('');
}
let deleteTargetId = null;
let renameTargetId = null;
let renameOriginalName = null;
window.showDeleteConfirm = function(id, name) {
deleteTargetId = id;
document.getElementById('deleteConfirmMessage').textContent = \`确定要删除文档集 "\${name}" 吗?此操作不可恢复。\`;
document.getElementById('deleteConfirmDialog').classList.add('active');
};
window.changeDocsetName = function(id, name) {
renameTargetId = id;
renameOriginalName = name;
document.getElementById('renameInput').value = name;
document.getElementById('renameDialog').classList.add('active');
setTimeout(() => document.getElementById('renameInput').focus(), 100);
};
window.closeDeleteConfirm = function() {
document.getElementById('deleteConfirmDialog').classList.remove('active');
deleteTargetId = null;
};
window.closeRenameDialog = function() {
document.getElementById('renameDialog').classList.remove('active');
renameTargetId = null;
renameOriginalName = null;
};
window.confirmDelete = function() {
if (deleteTargetId) {
vscode.postMessage({ command: 'deleteDocumentSet', id: deleteTargetId });
closeDeleteConfirm();
}
};
window.confirmRename = function() {
const newName = document.getElementById('renameInput').value.trim();
if (!newName) {
alert('请输入名称');
return;
}
if (newName !== renameOriginalName) {
vscode.postMessage({ command: 'changeDocumentSetName', id: renameTargetId, newName: newName });
}
closeRenameDialog();
};
window.addEventListener('message', event => {
const message = event.data;
if (message.command === 'filesSelectedForDocset') {
if (message.errors && message.errors.length > 0) {
alert('部分文件添加失败:\\n' + message.errors.join('\\n'));
}
const MAX_FILE_SIZE = 10 * 1024 * 1024;
const MAX_TOTAL_SIZE = 50 * 1024 * 1024;
const MAX_FILE_COUNT = 1000;
const vaildFiles = [];
const errors = [];
for (const file of message.files) {
if (file.size > MAX_FILE_SIZE) {
errors.push(\`\${file.name || file.absolutePath} 超过单个文件大小限制(\${formatFileSize(MAX_FILE_SIZE)}\`);
} else {
vaildFiles.push(file);
}
}
const newFiles = [...docsetFiles, ...vaildFiles];
const totalSize = newFiles.reduce((sum, f) => sum + (f.size || 0), 0);
if (newFiles.length > MAX_FILE_COUNT) {
errors.push(\`文档数量超过限制最多1000个当前数量\${newFiles.length} 个)\`);
return;
}
if (totalSize > MAX_TOTAL_SIZE) {
errors.push(\`文档集总大小超过 50MB 限制,当前大小为(\${formatFileSize(MAX_TOTAL_SIZE)}\`);
return;
}
if(errors.length > 0) {
alert('以下文件被跳过:\\n' + errors.join('\\n'));
}
docsetFiles = newFiles;
updateDocsetDisplay();
} else if (message.command === 'documentSetSaved') {
renderDocumentSets(message.documentSets);
}
});
`;
}