@qnote/q-ai-note 1.0.10 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/web/app.js +268 -9
- package/dist/web/index.html +5 -0
- package/dist/web/styles.css +63 -0
- package/package.json +1 -1
package/dist/web/app.js
CHANGED
|
@@ -45,6 +45,7 @@ const state = {
|
|
|
45
45
|
changesSandboxFilter: '',
|
|
46
46
|
changesTypeFilter: 'all',
|
|
47
47
|
changesQuickFilter: 'all',
|
|
48
|
+
workTreeExpandInitialized: false,
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
const expandedNodes = new Set();
|
|
@@ -331,6 +332,91 @@ function expandAllNodes() {
|
|
|
331
332
|
items.forEach(item => expandedNodes.add(item.id));
|
|
332
333
|
}
|
|
333
334
|
|
|
335
|
+
function buildWorkItemDepthMap(items) {
|
|
336
|
+
const byId = new Map(items.map((item) => [item.id, item]));
|
|
337
|
+
const memo = new Map();
|
|
338
|
+
const visiting = new Set();
|
|
339
|
+
const walk = (id) => {
|
|
340
|
+
if (memo.has(id)) return memo.get(id);
|
|
341
|
+
if (visiting.has(id)) return 0;
|
|
342
|
+
visiting.add(id);
|
|
343
|
+
const item = byId.get(id);
|
|
344
|
+
if (!item) {
|
|
345
|
+
visiting.delete(id);
|
|
346
|
+
return 0;
|
|
347
|
+
}
|
|
348
|
+
const parentId = item.parent_id;
|
|
349
|
+
const depth = parentId && byId.has(parentId) ? walk(parentId) + 1 : 0;
|
|
350
|
+
memo.set(id, depth);
|
|
351
|
+
visiting.delete(id);
|
|
352
|
+
return depth;
|
|
353
|
+
};
|
|
354
|
+
items.forEach((item) => walk(item.id));
|
|
355
|
+
return memo;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function getWorkTreeMaxDepth(items) {
|
|
359
|
+
const depthMap = buildWorkItemDepthMap(items || []);
|
|
360
|
+
let maxDepth = 0;
|
|
361
|
+
depthMap.forEach((depth) => {
|
|
362
|
+
if (Number.isFinite(depth)) maxDepth = Math.max(maxDepth, Number(depth));
|
|
363
|
+
});
|
|
364
|
+
return maxDepth;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function expandNodesToLevel(level, items) {
|
|
368
|
+
const safeLevel = Math.max(1, Number(level) || 1);
|
|
369
|
+
const depthMap = buildWorkItemDepthMap(items || []);
|
|
370
|
+
expandedNodes.clear();
|
|
371
|
+
(items || []).forEach((item) => {
|
|
372
|
+
const depth = Number(depthMap.get(item.id) || 0);
|
|
373
|
+
if (depth < safeLevel) expandedNodes.add(item.id);
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function applyWorkTreeCollapseAction(action) {
|
|
378
|
+
if (!state.currentSandbox) return;
|
|
379
|
+
const items = state.currentSandbox.items || [];
|
|
380
|
+
if (!items.length) return;
|
|
381
|
+
if (action === 'expand-all') {
|
|
382
|
+
expandedNodes.clear();
|
|
383
|
+
expandAllNodes();
|
|
384
|
+
} else if (action === 'collapse-all') {
|
|
385
|
+
expandedNodes.clear();
|
|
386
|
+
} else if (String(action || '').startsWith('collapse-level:')) {
|
|
387
|
+
const level = Number(String(action).split(':')[1] || '1');
|
|
388
|
+
expandNodesToLevel(level, items);
|
|
389
|
+
}
|
|
390
|
+
state.workTreeExpandInitialized = true;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function updateWorkTreeCollapseMenu(items) {
|
|
394
|
+
const selector = document.getElementById('work-tree-collapse-action');
|
|
395
|
+
if (!(selector instanceof HTMLSelectElement)) return;
|
|
396
|
+
const denseMode = state.workTreeViewMode === 'dense';
|
|
397
|
+
const hasItems = (items || []).length > 0;
|
|
398
|
+
selector.classList.toggle('hidden', !denseMode);
|
|
399
|
+
selector.disabled = !denseMode || !hasItems;
|
|
400
|
+
if (!denseMode || !hasItems) {
|
|
401
|
+
selector.innerHTML = '<option value="">层级操作</option>';
|
|
402
|
+
selector.value = '';
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const maxDepth = getWorkTreeMaxDepth(items);
|
|
406
|
+
const maxLevel = Math.max(1, maxDepth + 1);
|
|
407
|
+
const levelOptions = Array.from({ length: maxLevel }, (_v, idx) => {
|
|
408
|
+
const level = idx + 1;
|
|
409
|
+
return `<option value="collapse-level:${level}">折叠到 L${level}</option>`;
|
|
410
|
+
}).join('');
|
|
411
|
+
selector.innerHTML = `
|
|
412
|
+
<option value="">层级操作</option>
|
|
413
|
+
<option value="expand-all">全部展开</option>
|
|
414
|
+
<option value="collapse-all">全部折叠</option>
|
|
415
|
+
${levelOptions}
|
|
416
|
+
`;
|
|
417
|
+
selector.value = '';
|
|
418
|
+
}
|
|
419
|
+
|
|
334
420
|
function getRootNodeIds(items) {
|
|
335
421
|
return items.filter((item) => !item.parent_id).map((item) => item.id);
|
|
336
422
|
}
|
|
@@ -348,6 +434,8 @@ function applyWorkTreeViewMode(mode) {
|
|
|
348
434
|
} else {
|
|
349
435
|
expandAllNodes();
|
|
350
436
|
}
|
|
437
|
+
state.workTreeExpandInitialized = true;
|
|
438
|
+
updateWorkTreeCollapseMenu(items);
|
|
351
439
|
}
|
|
352
440
|
|
|
353
441
|
function applyWorkItemAssigneeToggle() {
|
|
@@ -374,13 +462,15 @@ function renderWorkTree() {
|
|
|
374
462
|
const entitySummaryByNodeId = buildNodeEntitySummaryByNodeId();
|
|
375
463
|
const entityRowsByNodeId = buildNodeEntityRowsByNodeId();
|
|
376
464
|
|
|
377
|
-
if (
|
|
465
|
+
if (!state.workTreeExpandInitialized && allItems.length > 0) {
|
|
378
466
|
if (state.workTreeViewMode === 'report') {
|
|
379
467
|
getRootNodeIds(allItems).forEach((id) => expandedNodes.add(id));
|
|
380
468
|
} else {
|
|
381
469
|
expandAllNodes();
|
|
382
470
|
}
|
|
471
|
+
state.workTreeExpandInitialized = true;
|
|
383
472
|
}
|
|
473
|
+
updateWorkTreeCollapseMenu(allItems);
|
|
384
474
|
|
|
385
475
|
if (allItems.length === 0) {
|
|
386
476
|
tree.innerHTML = `<div class="empty-state"><p>${treeReadonly ? '暂无任务' : '点击上方"添加"按钮创建第一个任务'}</p></div>`;
|
|
@@ -686,8 +776,49 @@ function populateParentSelect(items, preferredParentId = null) {
|
|
|
686
776
|
select.value = hasExpectedValue ? expectedValue : '';
|
|
687
777
|
}
|
|
688
778
|
|
|
689
|
-
function
|
|
690
|
-
|
|
779
|
+
function normalizeAssistantResponseText(raw) {
|
|
780
|
+
let text = String(raw || '').trim();
|
|
781
|
+
if (!text) return '';
|
|
782
|
+
// Recover nested response payload when parser fallback returns a JSON string.
|
|
783
|
+
for (let depth = 0; depth < 2; depth += 1) {
|
|
784
|
+
const maybeJson = text.trim();
|
|
785
|
+
if (!maybeJson.startsWith('{') || !maybeJson.endsWith('}')) break;
|
|
786
|
+
try {
|
|
787
|
+
const parsed = JSON.parse(maybeJson);
|
|
788
|
+
if (parsed && typeof parsed.response === 'string' && parsed.response.trim()) {
|
|
789
|
+
text = String(parsed.response).trim();
|
|
790
|
+
continue;
|
|
791
|
+
}
|
|
792
|
+
} catch {
|
|
793
|
+
// Ignore invalid json and keep original text.
|
|
794
|
+
}
|
|
795
|
+
break;
|
|
796
|
+
}
|
|
797
|
+
return text;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function unwrapMarkdownFence(rawText) {
|
|
801
|
+
const text = String(rawText || '').replace(/\r\n/g, '\n').trim();
|
|
802
|
+
const start = text.match(/^```(?:markdown|md)\s*\n?/i);
|
|
803
|
+
if (!start) return null;
|
|
804
|
+
let body = text.slice(start[0].length);
|
|
805
|
+
const endIdx = body.lastIndexOf('\n```');
|
|
806
|
+
if (endIdx >= 0) {
|
|
807
|
+
body = body.slice(0, endIdx);
|
|
808
|
+
} else {
|
|
809
|
+
body = body.replace(/```$/m, '');
|
|
810
|
+
}
|
|
811
|
+
return body.trim();
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function renderMarkdownSnippet(text, options = {}) {
|
|
815
|
+
const enableMermaid = Boolean(options.enableMermaid);
|
|
816
|
+
const normalizedSource = normalizeAssistantResponseText(text);
|
|
817
|
+
const fencedMarkdown = unwrapMarkdownFence(normalizedSource);
|
|
818
|
+
if (fencedMarkdown !== null) {
|
|
819
|
+
return renderMarkdownSnippet(fencedMarkdown, options);
|
|
820
|
+
}
|
|
821
|
+
const source = String(normalizedSource || '').replace(/\r\n/g, '\n');
|
|
691
822
|
const lines = source.split('\n');
|
|
692
823
|
const blocks = [];
|
|
693
824
|
let listItems = [];
|
|
@@ -711,12 +842,61 @@ function renderMarkdownSnippet(text) {
|
|
|
711
842
|
return html;
|
|
712
843
|
};
|
|
713
844
|
|
|
714
|
-
|
|
845
|
+
const splitTableCells = (line) => {
|
|
846
|
+
let raw = String(line || '').trim();
|
|
847
|
+
if (raw.startsWith('|')) raw = raw.slice(1);
|
|
848
|
+
if (raw.endsWith('|')) raw = raw.slice(0, -1);
|
|
849
|
+
return raw.split('|').map((cell) => String(cell || '').trim());
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
for (let idx = 0; idx < lines.length; idx += 1) {
|
|
853
|
+
const line = lines[idx];
|
|
715
854
|
const trimmed = line.trim();
|
|
716
855
|
if (!trimmed) {
|
|
717
856
|
flushList();
|
|
718
857
|
continue;
|
|
719
858
|
}
|
|
859
|
+
const fenceMatch = trimmed.match(/^```([a-zA-Z0-9_-]+)?\s*$/);
|
|
860
|
+
if (fenceMatch) {
|
|
861
|
+
flushList();
|
|
862
|
+
const fenceLang = String(fenceMatch[1] || '').toLowerCase();
|
|
863
|
+
const codeLines = [];
|
|
864
|
+
idx += 1;
|
|
865
|
+
while (idx < lines.length && !/^```/.test(String(lines[idx] || '').trim())) {
|
|
866
|
+
codeLines.push(lines[idx]);
|
|
867
|
+
idx += 1;
|
|
868
|
+
}
|
|
869
|
+
const code = codeLines.join('\n');
|
|
870
|
+
if (fenceLang === 'mermaid' && enableMermaid) {
|
|
871
|
+
blocks.push(`<div class="chat-mermaid" data-mermaid-code="${encodeURIComponent(code)}"></div>`);
|
|
872
|
+
} else {
|
|
873
|
+
blocks.push(`<pre><code>${safeText(code)}</code></pre>`);
|
|
874
|
+
}
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
if (trimmed.includes('|') && idx + 1 < lines.length) {
|
|
878
|
+
const nextTrimmed = String(lines[idx + 1] || '').trim();
|
|
879
|
+
const isTableDivider = /^\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?$/.test(nextTrimmed);
|
|
880
|
+
if (isTableDivider) {
|
|
881
|
+
flushList();
|
|
882
|
+
const headerCells = splitTableCells(trimmed);
|
|
883
|
+
const bodyRows = [];
|
|
884
|
+
idx += 2;
|
|
885
|
+
while (idx < lines.length) {
|
|
886
|
+
const row = String(lines[idx] || '').trim();
|
|
887
|
+
if (!row || !row.includes('|')) {
|
|
888
|
+
idx -= 1;
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
bodyRows.push(splitTableCells(row));
|
|
892
|
+
idx += 1;
|
|
893
|
+
}
|
|
894
|
+
const headerHtml = `<tr>${headerCells.map((cell) => `<th>${renderInline(cell)}</th>`).join('')}</tr>`;
|
|
895
|
+
const bodyHtml = bodyRows.map((cells) => `<tr>${cells.map((cell) => `<td>${renderInline(cell)}</td>`).join('')}</tr>`).join('');
|
|
896
|
+
blocks.push(`<table class="md-table"><thead>${headerHtml}</thead><tbody>${bodyHtml}</tbody></table>`);
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
720
900
|
if (/^[-*]\s+/.test(trimmed)) {
|
|
721
901
|
listItems.push(renderInline(trimmed.replace(/^[-*]\s+/, '')));
|
|
722
902
|
continue;
|
|
@@ -734,6 +914,73 @@ function renderMarkdownSnippet(text) {
|
|
|
734
914
|
return blocks.join('');
|
|
735
915
|
}
|
|
736
916
|
|
|
917
|
+
let mermaidLoadPromise = null;
|
|
918
|
+
|
|
919
|
+
function ensureMermaidRuntime() {
|
|
920
|
+
if (window.mermaid && typeof window.mermaid.render === 'function') {
|
|
921
|
+
return Promise.resolve(window.mermaid);
|
|
922
|
+
}
|
|
923
|
+
if (mermaidLoadPromise) return mermaidLoadPromise;
|
|
924
|
+
mermaidLoadPromise = new Promise((resolve, reject) => {
|
|
925
|
+
const existing = document.querySelector('script[data-mermaid-runtime="1"]');
|
|
926
|
+
if (existing) {
|
|
927
|
+
existing.addEventListener('load', () => {
|
|
928
|
+
if (window.mermaid && typeof window.mermaid.initialize === 'function') {
|
|
929
|
+
window.mermaid.initialize({ startOnLoad: false, securityLevel: 'strict' });
|
|
930
|
+
}
|
|
931
|
+
resolve(window.mermaid);
|
|
932
|
+
}, { once: true });
|
|
933
|
+
existing.addEventListener('error', () => reject(new Error('Mermaid script load failed')), { once: true });
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
const script = document.createElement('script');
|
|
937
|
+
script.src = 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js';
|
|
938
|
+
script.async = true;
|
|
939
|
+
script.setAttribute('data-mermaid-runtime', '1');
|
|
940
|
+
script.addEventListener('load', () => {
|
|
941
|
+
if (window.mermaid && typeof window.mermaid.initialize === 'function') {
|
|
942
|
+
window.mermaid.initialize({ startOnLoad: false, securityLevel: 'strict' });
|
|
943
|
+
}
|
|
944
|
+
resolve(window.mermaid);
|
|
945
|
+
}, { once: true });
|
|
946
|
+
script.addEventListener('error', () => reject(new Error('Mermaid script load failed')), { once: true });
|
|
947
|
+
document.head.appendChild(script);
|
|
948
|
+
});
|
|
949
|
+
return mermaidLoadPromise;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
async function renderMermaidInContainer(container) {
|
|
953
|
+
if (!(container instanceof HTMLElement)) return;
|
|
954
|
+
const blocks = Array.from(container.querySelectorAll('.chat-mermaid[data-mermaid-code]:not([data-mermaid-rendered="1"])'));
|
|
955
|
+
if (!blocks.length) return;
|
|
956
|
+
let mermaid = null;
|
|
957
|
+
try {
|
|
958
|
+
mermaid = await ensureMermaidRuntime();
|
|
959
|
+
} catch {
|
|
960
|
+
mermaid = null;
|
|
961
|
+
}
|
|
962
|
+
for (let idx = 0; idx < blocks.length; idx += 1) {
|
|
963
|
+
const block = blocks[idx];
|
|
964
|
+
const code = decodeURIComponent(String(block.getAttribute('data-mermaid-code') || ''));
|
|
965
|
+
if (!code) {
|
|
966
|
+
block.setAttribute('data-mermaid-rendered', '1');
|
|
967
|
+
continue;
|
|
968
|
+
}
|
|
969
|
+
if (mermaid && typeof mermaid.render === 'function') {
|
|
970
|
+
try {
|
|
971
|
+
const id = `chat-mermaid-${Date.now()}-${idx}`;
|
|
972
|
+
const rendered = await mermaid.render(id, code);
|
|
973
|
+
block.innerHTML = rendered?.svg || `<pre><code>${safeText(code)}</code></pre>`;
|
|
974
|
+
} catch {
|
|
975
|
+
block.innerHTML = `<pre><code>${safeText(code)}</code></pre>`;
|
|
976
|
+
}
|
|
977
|
+
} else {
|
|
978
|
+
block.innerHTML = `<pre><code>${safeText(code)}</code></pre>`;
|
|
979
|
+
}
|
|
980
|
+
block.setAttribute('data-mermaid-rendered', '1');
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
737
984
|
function getNodeById(nodeId) {
|
|
738
985
|
return state.currentSandbox?.items?.find((item) => item.id === nodeId) || null;
|
|
739
986
|
}
|
|
@@ -1453,6 +1700,7 @@ async function loadSandbox(id) {
|
|
|
1453
1700
|
apiRequest(`${API_BASE}/sandboxes/${id}/entities/stats`),
|
|
1454
1701
|
]);
|
|
1455
1702
|
state.currentSandbox = { ...sandbox, items, diaries };
|
|
1703
|
+
state.workTreeExpandInitialized = false;
|
|
1456
1704
|
state.nodeEntities = entities;
|
|
1457
1705
|
state.nodeEntityStats = entityStats;
|
|
1458
1706
|
|
|
@@ -1510,9 +1758,10 @@ async function loadSandboxChats(sandboxId) {
|
|
|
1510
1758
|
chats.map((chat) => renderChatEntry(chat, {
|
|
1511
1759
|
safeText,
|
|
1512
1760
|
renderAIActionMessage,
|
|
1513
|
-
renderContent: (content) => renderMarkdownSnippet(content),
|
|
1761
|
+
renderContent: (content) => renderMarkdownSnippet(content, { enableMermaid: true }),
|
|
1514
1762
|
})),
|
|
1515
1763
|
);
|
|
1764
|
+
await renderMermaidInContainer(messages);
|
|
1516
1765
|
|
|
1517
1766
|
messages.scrollTop = messages.scrollHeight;
|
|
1518
1767
|
}
|
|
@@ -1544,7 +1793,7 @@ function renderAIActionMessage(action) {
|
|
|
1544
1793
|
};
|
|
1545
1794
|
|
|
1546
1795
|
if (actionType === 'response' || actionType === 'clarify') {
|
|
1547
|
-
return `<div class="chat-message assistant">${renderMarkdownSnippet(action.response || action.observation || '')}</div>`;
|
|
1796
|
+
return `<div class="chat-message assistant">${renderMarkdownSnippet(action.response || action.observation || '', { enableMermaid: true })}</div>`;
|
|
1548
1797
|
}
|
|
1549
1798
|
else if (actionType === 'confirm' && action.confirm_items) {
|
|
1550
1799
|
// Skip confirm, go directly to done
|
|
@@ -1571,7 +1820,7 @@ function renderAIActionMessage(action) {
|
|
|
1571
1820
|
</div>`;
|
|
1572
1821
|
}
|
|
1573
1822
|
|
|
1574
|
-
return `<div class="chat-message assistant">${renderMarkdownSnippet(action.response || '')}</div>`;
|
|
1823
|
+
return `<div class="chat-message assistant">${renderMarkdownSnippet(action.response || '', { enableMermaid: true })}</div>`;
|
|
1575
1824
|
}
|
|
1576
1825
|
|
|
1577
1826
|
window.undoOperation = async function(operationId, btn) {
|
|
@@ -2575,7 +2824,8 @@ async function initApp() {
|
|
|
2575
2824
|
const actionType = action.action;
|
|
2576
2825
|
|
|
2577
2826
|
if (actionType === 'response' || actionType === 'clarify') {
|
|
2578
|
-
messages.insertAdjacentHTML('beforeend', `<div class="chat-message assistant">${renderMarkdownSnippet(action.response || action.observation || '')}</div>`);
|
|
2827
|
+
messages.insertAdjacentHTML('beforeend', `<div class="chat-message assistant">${renderMarkdownSnippet(action.response || action.observation || '', { enableMermaid: true })}</div>`);
|
|
2828
|
+
await renderMermaidInContainer(messages);
|
|
2579
2829
|
messages.scrollTop = messages.scrollHeight;
|
|
2580
2830
|
|
|
2581
2831
|
if (actionType === 'clarify') {
|
|
@@ -2663,11 +2913,13 @@ async function initApp() {
|
|
|
2663
2913
|
}
|
|
2664
2914
|
else if (actionType === 'done') {
|
|
2665
2915
|
messages.insertAdjacentHTML('beforeend', renderAIActionMessage(action));
|
|
2916
|
+
await renderMermaidInContainer(messages);
|
|
2666
2917
|
messages.scrollTop = messages.scrollHeight;
|
|
2667
2918
|
state.pendingAction = null;
|
|
2668
2919
|
}
|
|
2669
2920
|
else if (actionType === 'stop') {
|
|
2670
|
-
messages.insertAdjacentHTML('beforeend', `<div class="chat-message assistant">${renderMarkdownSnippet(action.observation || '已取消操作')}</div>`);
|
|
2921
|
+
messages.insertAdjacentHTML('beforeend', `<div class="chat-message assistant">${renderMarkdownSnippet(action.observation || '已取消操作', { enableMermaid: true })}</div>`);
|
|
2922
|
+
await renderMermaidInContainer(messages);
|
|
2671
2923
|
messages.scrollTop = messages.scrollHeight;
|
|
2672
2924
|
state.pendingAction = null;
|
|
2673
2925
|
}
|
|
@@ -3012,6 +3264,13 @@ async function initApp() {
|
|
|
3012
3264
|
renderWorkTree();
|
|
3013
3265
|
});
|
|
3014
3266
|
|
|
3267
|
+
document.getElementById('work-tree-collapse-action')?.addEventListener('change', (e) => {
|
|
3268
|
+
const action = e.target.value || '';
|
|
3269
|
+
if (!action) return;
|
|
3270
|
+
applyWorkTreeCollapseAction(action);
|
|
3271
|
+
renderWorkTree();
|
|
3272
|
+
});
|
|
3273
|
+
|
|
3015
3274
|
document.getElementById('work-item-element-preview-mode')?.addEventListener('change', (e) => {
|
|
3016
3275
|
state.workItemElementPreviewMode = e.target.value || 'none';
|
|
3017
3276
|
renderWorkTree();
|
package/dist/web/index.html
CHANGED
|
@@ -63,6 +63,11 @@
|
|
|
63
63
|
<option value="report">汇报折叠模式</option>
|
|
64
64
|
<option value="dense">树模式</option>
|
|
65
65
|
</select>
|
|
66
|
+
<select id="work-tree-collapse-action" title="树模式层级操作">
|
|
67
|
+
<option value="">层级操作</option>
|
|
68
|
+
<option value="expand-all">全部展开</option>
|
|
69
|
+
<option value="collapse-all">全部折叠</option>
|
|
70
|
+
</select>
|
|
66
71
|
<select id="work-item-element-preview-mode">
|
|
67
72
|
<option value="none">能力要素:不显示</option>
|
|
68
73
|
<option value="issue">能力要素:Issue</option>
|
package/dist/web/styles.css
CHANGED
|
@@ -221,6 +221,10 @@ h2 {
|
|
|
221
221
|
gap: 8px;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
#work-tree-collapse-action {
|
|
225
|
+
min-width: 132px;
|
|
226
|
+
}
|
|
227
|
+
|
|
224
228
|
.inline-checkbox {
|
|
225
229
|
display: inline-flex;
|
|
226
230
|
align-items: center;
|
|
@@ -1200,6 +1204,65 @@ h2 {
|
|
|
1200
1204
|
border-bottom-left-radius: 4px;
|
|
1201
1205
|
}
|
|
1202
1206
|
|
|
1207
|
+
.chat-message.assistant h1,
|
|
1208
|
+
.chat-message.assistant h2,
|
|
1209
|
+
.chat-message.assistant h3,
|
|
1210
|
+
.chat-message.assistant h4 {
|
|
1211
|
+
margin: 2px 0 6px;
|
|
1212
|
+
line-height: 1.35;
|
|
1213
|
+
font-weight: 600;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
.chat-message.assistant h1 {
|
|
1217
|
+
font-size: 16px;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
.chat-message.assistant h2 {
|
|
1221
|
+
font-size: 15px;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
.chat-message.assistant h3,
|
|
1225
|
+
.chat-message.assistant h4 {
|
|
1226
|
+
font-size: 14px;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
.chat-message.assistant p,
|
|
1230
|
+
.chat-message.assistant ul,
|
|
1231
|
+
.chat-message.assistant ol,
|
|
1232
|
+
.chat-message.assistant pre {
|
|
1233
|
+
margin: 4px 0;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
.chat-message.assistant .md-table {
|
|
1237
|
+
border-collapse: collapse;
|
|
1238
|
+
width: 100%;
|
|
1239
|
+
margin: 6px 0;
|
|
1240
|
+
font-size: 12px;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.chat-message.assistant .md-table th,
|
|
1244
|
+
.chat-message.assistant .md-table td {
|
|
1245
|
+
border: 1px solid #d5deed;
|
|
1246
|
+
padding: 4px 6px;
|
|
1247
|
+
text-align: left;
|
|
1248
|
+
vertical-align: top;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
.chat-message.assistant .md-table th {
|
|
1252
|
+
background: #eef4ff;
|
|
1253
|
+
font-weight: 600;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
.chat-message.assistant .chat-mermaid {
|
|
1257
|
+
width: 100%;
|
|
1258
|
+
overflow-x: auto;
|
|
1259
|
+
background: #fff;
|
|
1260
|
+
border: 1px solid #d5deed;
|
|
1261
|
+
border-radius: 8px;
|
|
1262
|
+
padding: 6px;
|
|
1263
|
+
margin: 6px 0;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1203
1266
|
.chat-message.assistant.loading {
|
|
1204
1267
|
color: var(--text-secondary);
|
|
1205
1268
|
font-style: italic;
|