@qnote/q-ai-note 1.0.8 → 1.0.9
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 +56 -12
- package/dist/web/chatView.js +5 -1
- package/dist/web/styles.css +24 -0
- package/dist/web/vueRenderers.js +99 -1
- package/package.json +1 -1
package/dist/web/app.js
CHANGED
|
@@ -487,16 +487,50 @@ function renderWorkTree() {
|
|
|
487
487
|
});
|
|
488
488
|
await loadSandbox(state.currentSandbox.id);
|
|
489
489
|
},
|
|
490
|
-
onReorderLanes: treeReadonly ? undefined : async (dragRootId, targetRootId) => {
|
|
490
|
+
onReorderLanes: treeReadonly ? undefined : async (dragRootId, targetRootId, position = 'before') => {
|
|
491
491
|
if (!state.currentSandbox) return;
|
|
492
|
-
if (!dragRootId
|
|
492
|
+
if (!dragRootId) return;
|
|
493
|
+
if (targetRootId && dragRootId === targetRootId) return;
|
|
493
494
|
const roots = (state.currentSandbox.items || []).filter((item) => !item.parent_id);
|
|
494
495
|
const ordered = [...roots].sort((a, b) => compareSiblingOrder(a, b, 'lane_order_key'));
|
|
496
|
+
const missingLaneKeyRoots = ordered.filter((item) => !getNodeOrderKey(item, 'lane_order_key'));
|
|
497
|
+
if (missingLaneKeyRoots.length > 0) {
|
|
498
|
+
let leftKey = '';
|
|
499
|
+
for (const root of ordered) {
|
|
500
|
+
const currentKey = getNodeOrderKey(root, 'lane_order_key');
|
|
501
|
+
if (currentKey) {
|
|
502
|
+
leftKey = currentKey;
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
const generatedKey = rankBetween(leftKey, '');
|
|
506
|
+
await apiRequest(`${API_BASE}/items/${root.id}`, {
|
|
507
|
+
method: 'PUT',
|
|
508
|
+
body: JSON.stringify({
|
|
509
|
+
extra_data: {
|
|
510
|
+
...(root.extra_data || {}),
|
|
511
|
+
lane_order_key: generatedKey,
|
|
512
|
+
},
|
|
513
|
+
}),
|
|
514
|
+
});
|
|
515
|
+
root.extra_data = {
|
|
516
|
+
...(root.extra_data || {}),
|
|
517
|
+
lane_order_key: generatedKey,
|
|
518
|
+
};
|
|
519
|
+
leftKey = generatedKey;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
495
522
|
const fromIdx = ordered.findIndex((item) => item.id === dragRootId);
|
|
496
|
-
|
|
497
|
-
if (fromIdx < 0 || toIdx < 0) return;
|
|
523
|
+
if (fromIdx < 0) return;
|
|
498
524
|
const [moved] = ordered.splice(fromIdx, 1);
|
|
499
|
-
ordered.
|
|
525
|
+
let insertIndex = ordered.length;
|
|
526
|
+
if (targetRootId) {
|
|
527
|
+
const targetIdx = ordered.findIndex((item) => item.id === targetRootId);
|
|
528
|
+
if (targetIdx < 0) return;
|
|
529
|
+
insertIndex = position === 'after' ? targetIdx + 1 : targetIdx;
|
|
530
|
+
} else if (position !== 'end') {
|
|
531
|
+
insertIndex = ordered.length;
|
|
532
|
+
}
|
|
533
|
+
ordered.splice(insertIndex, 0, moved);
|
|
500
534
|
const movedIndex = ordered.findIndex((item) => item.id === dragRootId);
|
|
501
535
|
const left = ordered[movedIndex - 1] || null;
|
|
502
536
|
const right = ordered[movedIndex + 1] || null;
|
|
@@ -623,7 +657,7 @@ function getNodeOrderKey(item, keyName = 'order_key') {
|
|
|
623
657
|
function compareSiblingOrder(a, b, keyName = 'order_key') {
|
|
624
658
|
const keyA = getNodeOrderKey(a, keyName);
|
|
625
659
|
const keyB = getNodeOrderKey(b, keyName);
|
|
626
|
-
if (keyA && keyB && keyA !== keyB) return keyA
|
|
660
|
+
if (keyA && keyB && keyA !== keyB) return keyA < keyB ? -1 : 1;
|
|
627
661
|
if (keyA && !keyB) return -1;
|
|
628
662
|
if (!keyA && keyB) return 1;
|
|
629
663
|
const numericA = Number(a?.extra_data?.lane_order);
|
|
@@ -633,7 +667,10 @@ function compareSiblingOrder(a, b, keyName = 'order_key') {
|
|
|
633
667
|
if (keyName === 'lane_order_key' && validA && validB && numericA !== numericB) return numericA - numericB;
|
|
634
668
|
if (keyName === 'lane_order_key' && validA && !validB) return -1;
|
|
635
669
|
if (keyName === 'lane_order_key' && !validA && validB) return 1;
|
|
636
|
-
|
|
670
|
+
const createdA = String(a?.created_at || '');
|
|
671
|
+
const createdB = String(b?.created_at || '');
|
|
672
|
+
if (createdA === createdB) return 0;
|
|
673
|
+
return createdA < createdB ? -1 : 1;
|
|
637
674
|
}
|
|
638
675
|
|
|
639
676
|
function populateParentSelect(items, preferredParentId = null) {
|
|
@@ -1468,7 +1505,14 @@ async function loadSandboxChats(sandboxId) {
|
|
|
1468
1505
|
const chats = await apiRequest(`${API_BASE}/chats/sandbox/${sandboxId}`);
|
|
1469
1506
|
state.chats = chats;
|
|
1470
1507
|
|
|
1471
|
-
mountHtmlList(
|
|
1508
|
+
mountHtmlList(
|
|
1509
|
+
'sandbox-chat-messages',
|
|
1510
|
+
chats.map((chat) => renderChatEntry(chat, {
|
|
1511
|
+
safeText,
|
|
1512
|
+
renderAIActionMessage,
|
|
1513
|
+
renderContent: (content) => renderMarkdownSnippet(content),
|
|
1514
|
+
})),
|
|
1515
|
+
);
|
|
1472
1516
|
|
|
1473
1517
|
messages.scrollTop = messages.scrollHeight;
|
|
1474
1518
|
}
|
|
@@ -1500,7 +1544,7 @@ function renderAIActionMessage(action) {
|
|
|
1500
1544
|
};
|
|
1501
1545
|
|
|
1502
1546
|
if (actionType === 'response' || actionType === 'clarify') {
|
|
1503
|
-
return `<div class="chat-message assistant">${
|
|
1547
|
+
return `<div class="chat-message assistant">${renderMarkdownSnippet(action.response || action.observation || '')}</div>`;
|
|
1504
1548
|
}
|
|
1505
1549
|
else if (actionType === 'confirm' && action.confirm_items) {
|
|
1506
1550
|
// Skip confirm, go directly to done
|
|
@@ -1527,7 +1571,7 @@ function renderAIActionMessage(action) {
|
|
|
1527
1571
|
</div>`;
|
|
1528
1572
|
}
|
|
1529
1573
|
|
|
1530
|
-
return `<div class="chat-message assistant">${
|
|
1574
|
+
return `<div class="chat-message assistant">${renderMarkdownSnippet(action.response || '')}</div>`;
|
|
1531
1575
|
}
|
|
1532
1576
|
|
|
1533
1577
|
window.undoOperation = async function(operationId, btn) {
|
|
@@ -2531,7 +2575,7 @@ async function initApp() {
|
|
|
2531
2575
|
const actionType = action.action;
|
|
2532
2576
|
|
|
2533
2577
|
if (actionType === 'response' || actionType === 'clarify') {
|
|
2534
|
-
messages.insertAdjacentHTML('beforeend', `<div class="chat-message assistant">${
|
|
2578
|
+
messages.insertAdjacentHTML('beforeend', `<div class="chat-message assistant">${renderMarkdownSnippet(action.response || action.observation || '')}</div>`);
|
|
2535
2579
|
messages.scrollTop = messages.scrollHeight;
|
|
2536
2580
|
|
|
2537
2581
|
if (actionType === 'clarify') {
|
|
@@ -2623,7 +2667,7 @@ async function initApp() {
|
|
|
2623
2667
|
state.pendingAction = null;
|
|
2624
2668
|
}
|
|
2625
2669
|
else if (actionType === 'stop') {
|
|
2626
|
-
messages.insertAdjacentHTML('beforeend', `<div class="chat-message assistant">${
|
|
2670
|
+
messages.insertAdjacentHTML('beforeend', `<div class="chat-message assistant">${renderMarkdownSnippet(action.observation || '已取消操作')}</div>`);
|
|
2627
2671
|
messages.scrollTop = messages.scrollHeight;
|
|
2628
2672
|
state.pendingAction = null;
|
|
2629
2673
|
}
|
package/dist/web/chatView.js
CHANGED
|
@@ -14,7 +14,7 @@ export function tryParseAssistantAction(content) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function renderChatEntry(chat, helpers) {
|
|
17
|
-
const { safeText, renderAIActionMessage } = helpers;
|
|
17
|
+
const { safeText, renderAIActionMessage, renderContent } = helpers;
|
|
18
18
|
|
|
19
19
|
if (!('role' in chat)) {
|
|
20
20
|
return `<div class="chat-message diary">[日记] ${safeText(chat.content)}</div>`;
|
|
@@ -25,6 +25,10 @@ export function renderChatEntry(chat, helpers) {
|
|
|
25
25
|
if (parsedAction) {
|
|
26
26
|
return renderAIActionMessage(parsedAction);
|
|
27
27
|
}
|
|
28
|
+
const contentHtml = typeof renderContent === 'function'
|
|
29
|
+
? renderContent(chat.content)
|
|
30
|
+
: safeText(chat.content);
|
|
31
|
+
return `<div class="chat-message assistant">${contentHtml}</div>`;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
return `<div class="chat-message ${chat.role}">${safeText(chat.content)}</div>`;
|
package/dist/web/styles.css
CHANGED
|
@@ -647,6 +647,30 @@ h2 {
|
|
|
647
647
|
flex-wrap: nowrap;
|
|
648
648
|
}
|
|
649
649
|
|
|
650
|
+
.dense-lane-drop-slot {
|
|
651
|
+
width: 14px;
|
|
652
|
+
min-width: 14px;
|
|
653
|
+
align-self: stretch;
|
|
654
|
+
border-radius: 6px;
|
|
655
|
+
min-height: 180px;
|
|
656
|
+
transition: background-color 0.15s ease, box-shadow 0.15s ease;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.dense-lane-drop-slot.end {
|
|
660
|
+
width: 24px;
|
|
661
|
+
min-width: 24px;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.dense-lane-drop-slot.lane-slot-drag-over {
|
|
665
|
+
background: rgba(59, 130, 246, 0.28);
|
|
666
|
+
box-shadow: inset 0 0 0 1px rgba(59, 130, 246, 0.45);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
.dense-lane-board.is-lane-dragging-active .dense-lane-drop-slot {
|
|
670
|
+
background: rgba(148, 163, 184, 0.14);
|
|
671
|
+
box-shadow: inset 0 0 0 1px rgba(148, 163, 184, 0.22);
|
|
672
|
+
}
|
|
673
|
+
|
|
650
674
|
.dense-lane {
|
|
651
675
|
min-width: var(--lane-width, 220px);
|
|
652
676
|
width: var(--lane-width, 220px);
|
package/dist/web/vueRenderers.js
CHANGED
|
@@ -411,6 +411,7 @@ function renderDenseTree(roots, byParent, expandedIdSet, entitySummaryByNodeId,
|
|
|
411
411
|
const laneWidth = getDenseLaneWidthPx(root, byParent, showAssignee);
|
|
412
412
|
const laneNameMax = Math.max(120, laneWidth - 86);
|
|
413
413
|
return `
|
|
414
|
+
<div class="dense-lane-drop-slot" data-lane-slot-root-id="${esc(root.id)}" data-lane-slot-position="before" title="拖拽到此处:插入到当前泳道之前"></div>
|
|
414
415
|
<section class="dense-lane" data-root-id="${esc(root.id)}" style="--lane-width:${laneWidth}px;--lane-name-max:${laneNameMax}px;">
|
|
415
416
|
${readonly ? '' : `<div class="dense-lane-drag-handle" data-lane-drag-id="${esc(root.id)}" draggable="true" title="拖拽调整泳道顺序">⋮⋮</div>`}
|
|
416
417
|
<div class="dense-lane-body">
|
|
@@ -419,6 +420,7 @@ function renderDenseTree(roots, byParent, expandedIdSet, entitySummaryByNodeId,
|
|
|
419
420
|
</section>
|
|
420
421
|
`;
|
|
421
422
|
}).join('')}
|
|
423
|
+
<div class="dense-lane-drop-slot end" data-lane-slot-end="1" title="拖拽到此处:移动到最后"></div>
|
|
422
424
|
</div>
|
|
423
425
|
`;
|
|
424
426
|
}
|
|
@@ -608,12 +610,16 @@ export function mountWorkTree(targetId, options) {
|
|
|
608
610
|
});
|
|
609
611
|
|
|
610
612
|
const laneEls = Array.from(container.querySelectorAll('.dense-lane[data-root-id]'));
|
|
613
|
+
const laneSlotEls = Array.from(container.querySelectorAll('.dense-lane-drop-slot[data-lane-slot-root-id]'));
|
|
614
|
+
const laneEndSlotEl = container.querySelector('.dense-lane-drop-slot[data-lane-slot-end="1"]');
|
|
615
|
+
const laneDropPositionByRootId = new Map();
|
|
611
616
|
const laneHandleEls = Array.from(container.querySelectorAll('.dense-lane-drag-handle[data-lane-drag-id]'));
|
|
612
617
|
laneHandleEls.forEach((handle) => {
|
|
613
618
|
const rootId = handle.getAttribute('data-lane-drag-id') || '';
|
|
614
619
|
handle.addEventListener('dragstart', (event) => {
|
|
615
620
|
draggingLaneId = rootId;
|
|
616
621
|
draggingNodeId = '';
|
|
622
|
+
board?.classList.add('is-lane-dragging-active');
|
|
617
623
|
const lane = handle.closest('.dense-lane');
|
|
618
624
|
lane?.classList.add('is-lane-dragging');
|
|
619
625
|
event.dataTransfer?.setData('text/plain', rootId);
|
|
@@ -622,6 +628,14 @@ export function mountWorkTree(targetId, options) {
|
|
|
622
628
|
handle.addEventListener('dragend', () => {
|
|
623
629
|
const lane = handle.closest('.dense-lane');
|
|
624
630
|
lane?.classList.remove('is-lane-dragging');
|
|
631
|
+
board?.classList.remove('is-lane-dragging-active');
|
|
632
|
+
laneEls.forEach((laneEl) => {
|
|
633
|
+
laneEl.classList.remove('lane-drag-over-target');
|
|
634
|
+
laneEl.removeAttribute('data-lane-drop-position');
|
|
635
|
+
});
|
|
636
|
+
laneSlotEls.forEach((slotEl) => slotEl.classList.remove('lane-slot-drag-over'));
|
|
637
|
+
laneEndSlotEl?.classList.remove('lane-slot-drag-over');
|
|
638
|
+
laneDropPositionByRootId.clear();
|
|
625
639
|
draggingLaneId = '';
|
|
626
640
|
});
|
|
627
641
|
});
|
|
@@ -630,17 +644,101 @@ export function mountWorkTree(targetId, options) {
|
|
|
630
644
|
el.addEventListener('dragover', (event) => {
|
|
631
645
|
if (!draggingLaneId || draggingLaneId === rootId) return;
|
|
632
646
|
event.preventDefault();
|
|
647
|
+
const rect = el.getBoundingClientRect();
|
|
648
|
+
const offsetX = event.clientX - rect.left;
|
|
649
|
+
const ratio = rect.width > 0 ? offsetX / rect.width : 0.5;
|
|
650
|
+
const laneDropPosition = ratio >= 0.5 ? 'after' : 'before';
|
|
651
|
+
laneDropPositionByRootId.set(rootId, laneDropPosition);
|
|
652
|
+
el.setAttribute('data-lane-drop-position', laneDropPosition);
|
|
633
653
|
el.classList.add('lane-drag-over-target');
|
|
634
654
|
});
|
|
635
655
|
el.addEventListener('dragleave', () => {
|
|
636
656
|
el.classList.remove('lane-drag-over-target');
|
|
657
|
+
el.removeAttribute('data-lane-drop-position');
|
|
658
|
+
laneDropPositionByRootId.delete(rootId);
|
|
637
659
|
});
|
|
638
660
|
el.addEventListener('drop', (event) => {
|
|
639
661
|
event.preventDefault();
|
|
640
662
|
el.classList.remove('lane-drag-over-target');
|
|
663
|
+
let laneDropPosition = laneDropPositionByRootId.get(rootId);
|
|
664
|
+
if (!laneDropPosition) {
|
|
665
|
+
const rect = el.getBoundingClientRect();
|
|
666
|
+
const offsetX = event.clientX - rect.left;
|
|
667
|
+
const ratio = rect.width > 0 ? offsetX / rect.width : 0.5;
|
|
668
|
+
laneDropPosition = ratio >= 0.5 ? 'after' : 'before';
|
|
669
|
+
}
|
|
670
|
+
el.removeAttribute('data-lane-drop-position');
|
|
671
|
+
laneDropPositionByRootId.delete(rootId);
|
|
641
672
|
if (!draggingLaneId || draggingLaneId === rootId) return;
|
|
642
|
-
|
|
673
|
+
if (laneDropPosition === 'before') {
|
|
674
|
+
event.stopPropagation();
|
|
675
|
+
onReorderLanes?.(draggingLaneId, rootId, 'before');
|
|
676
|
+
board?.classList.remove('is-lane-dragging-active');
|
|
677
|
+
draggingLaneId = '';
|
|
678
|
+
} else {
|
|
679
|
+
const orderedRootIds = laneEls
|
|
680
|
+
.map((laneEl) => laneEl.getAttribute('data-root-id') || '')
|
|
681
|
+
.filter((id) => id && id !== draggingLaneId);
|
|
682
|
+
const isLastTarget = orderedRootIds.length > 0 && orderedRootIds[orderedRootIds.length - 1] === rootId;
|
|
683
|
+
if (!isLastTarget) {
|
|
684
|
+
event.stopPropagation();
|
|
685
|
+
onReorderLanes?.(draggingLaneId, rootId, 'after');
|
|
686
|
+
board?.classList.remove('is-lane-dragging-active');
|
|
687
|
+
draggingLaneId = '';
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
});
|
|
692
|
+
laneSlotEls.forEach((slotEl) => {
|
|
693
|
+
const targetRootId = slotEl.getAttribute('data-lane-slot-root-id') || '';
|
|
694
|
+
slotEl.addEventListener('dragover', (event) => {
|
|
695
|
+
if (!draggingLaneId || draggingLaneId === targetRootId) return;
|
|
696
|
+
event.preventDefault();
|
|
697
|
+
slotEl.classList.add('lane-slot-drag-over');
|
|
698
|
+
});
|
|
699
|
+
slotEl.addEventListener('dragleave', () => {
|
|
700
|
+
slotEl.classList.remove('lane-slot-drag-over');
|
|
701
|
+
});
|
|
702
|
+
slotEl.addEventListener('drop', (event) => {
|
|
703
|
+
event.preventDefault();
|
|
704
|
+
event.stopPropagation();
|
|
705
|
+
slotEl.classList.remove('lane-slot-drag-over');
|
|
706
|
+
if (!draggingLaneId || draggingLaneId === targetRootId) return;
|
|
707
|
+
onReorderLanes?.(draggingLaneId, targetRootId, 'before');
|
|
708
|
+
board?.classList.remove('is-lane-dragging-active');
|
|
643
709
|
draggingLaneId = '';
|
|
644
710
|
});
|
|
645
711
|
});
|
|
712
|
+
laneEndSlotEl?.addEventListener('dragover', (event) => {
|
|
713
|
+
if (!draggingLaneId) return;
|
|
714
|
+
event.preventDefault();
|
|
715
|
+
laneEndSlotEl.classList.add('lane-slot-drag-over');
|
|
716
|
+
});
|
|
717
|
+
laneEndSlotEl?.addEventListener('dragleave', () => {
|
|
718
|
+
laneEndSlotEl.classList.remove('lane-slot-drag-over');
|
|
719
|
+
});
|
|
720
|
+
laneEndSlotEl?.addEventListener('drop', (event) => {
|
|
721
|
+
if (!draggingLaneId) return;
|
|
722
|
+
event.preventDefault();
|
|
723
|
+
event.stopPropagation();
|
|
724
|
+
laneEndSlotEl.classList.remove('lane-slot-drag-over');
|
|
725
|
+
onReorderLanes?.(draggingLaneId, '', 'end');
|
|
726
|
+
board?.classList.remove('is-lane-dragging-active');
|
|
727
|
+
draggingLaneId = '';
|
|
728
|
+
});
|
|
729
|
+
board?.addEventListener('dragover', (event) => {
|
|
730
|
+
if (!draggingLaneId) return;
|
|
731
|
+
event.preventDefault();
|
|
732
|
+
});
|
|
733
|
+
board?.addEventListener('drop', (event) => {
|
|
734
|
+
if (!draggingLaneId) return;
|
|
735
|
+
event.preventDefault();
|
|
736
|
+
laneEls.forEach((laneEl) => {
|
|
737
|
+
laneEl.classList.remove('lane-drag-over-target');
|
|
738
|
+
laneEl.removeAttribute('data-lane-drop-position');
|
|
739
|
+
});
|
|
740
|
+
laneDropPositionByRootId.clear();
|
|
741
|
+
onReorderLanes?.(draggingLaneId, '', 'end');
|
|
742
|
+
draggingLaneId = '';
|
|
743
|
+
});
|
|
646
744
|
}
|