Skip to content

Commit ea9419f

Browse files
authored
Merge pull request Stack-Cairn#231 from AlphaCatMeow/feat/provider-models-list-ux
feat(供应商): 增强模型列表排序与批量操作
2 parents 6abc0be + 00ff883 commit ea9419f

22 files changed

Lines changed: 2844 additions & 227 deletions

File tree

crates/agent-gateway/web/src/components/project-tools/rightDockModel.ts

Lines changed: 31 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
import {
2+
applyDragInsertIndex,
3+
clampDragOffset,
4+
computeDragAutoScrollVelocity,
5+
computeDragInsertIndex,
6+
computeDragShiftOffsets,
7+
REORDER_AUTO_SCROLL_EDGE_PX,
8+
REORDER_AUTO_SCROLL_MAX_STEP_PX,
9+
reorderIdsByKeyboard,
10+
} from "../../lib/reorder/reorderModel";
111
import {
212
RIGHT_DOCK_SINGLETON_TAB_IDS,
313
RIGHT_DOCK_TOOL_KINDS,
@@ -190,22 +200,11 @@ export function computeTabDragInsertIndex(
190200
draggedId: string,
191201
draggedOffset: number,
192202
) {
193-
const draggedIndex = slots.findIndex((slot) => slot.id === draggedId);
194-
const dragged = slots[draggedIndex];
195-
if (!dragged) return 0;
196-
const draggedLeft = dragged.left + draggedOffset;
197-
const draggedRight = draggedLeft + dragged.width;
198-
let index = 0;
199-
for (let slotIndex = 0; slotIndex < slots.length; slotIndex += 1) {
200-
if (slotIndex === draggedIndex) continue;
201-
const slot = slots[slotIndex];
202-
if (!slot) continue;
203-
const midpoint = slot.left + slot.width / 2;
204-
const staysBefore =
205-
slotIndex < draggedIndex ? midpoint <= draggedLeft : midpoint < draggedRight;
206-
if (staysBefore) index += 1;
207-
}
208-
return index;
203+
return computeDragInsertIndex(
204+
slots.map((slot) => ({ id: slot.id, start: slot.left, size: slot.width })),
205+
draggedId,
206+
draggedOffset,
207+
);
209208
}
210209

211210
// Final id order produced by dropping the dragged tab at `insertIndex` among
@@ -215,10 +214,7 @@ export function applyTabDragInsertIndex(
215214
draggedId: string,
216215
insertIndex: number,
217216
) {
218-
const others = order.filter((id) => id !== draggedId);
219-
if (others.length === order.length) return [...order];
220-
const index = Math.max(0, Math.min(others.length, insertIndex));
221-
return [...others.slice(0, index), draggedId, ...others.slice(index)];
217+
return applyDragInsertIndex(order, draggedId, insertIndex);
222218
}
223219

224220
// translateX per non-dragged tab while the dragged tab hovers at
@@ -230,24 +226,12 @@ export function computeTabShiftOffsets(
230226
insertIndex: number,
231227
gap: number,
232228
) {
233-
const draggedIndex = slots.findIndex((slot) => slot.id === draggedId);
234-
const dragged = slots[draggedIndex];
235-
if (!dragged) return {};
236-
const step = dragged.width + gap;
237-
const shifts: Record<string, number> = {};
238-
let otherIndex = 0;
239-
for (let index = 0; index < slots.length; index += 1) {
240-
if (index === draggedIndex) continue;
241-
const slot = slots[index];
242-
if (!slot) continue;
243-
if (index < draggedIndex && otherIndex >= insertIndex) {
244-
shifts[slot.id] = step;
245-
} else if (index > draggedIndex && otherIndex < insertIndex) {
246-
shifts[slot.id] = -step;
247-
}
248-
otherIndex += 1;
249-
}
250-
return shifts;
229+
return computeDragShiftOffsets(
230+
slots.map((slot) => ({ id: slot.id, start: slot.left, size: slot.width })),
231+
draggedId,
232+
insertIndex,
233+
gap,
234+
);
251235
}
252236

253237
// Keeps the dragged tab inside the strip's content bounds.
@@ -256,21 +240,15 @@ export function clampTabDragOffset(
256240
draggedId: string,
257241
offset: number,
258242
) {
259-
const dragged = slots.find((slot) => slot.id === draggedId);
260-
if (!dragged) return 0;
261-
let minLeft = dragged.left;
262-
let maxRight = dragged.left + dragged.width;
263-
for (const slot of slots) {
264-
minLeft = Math.min(minLeft, slot.left);
265-
maxRight = Math.max(maxRight, slot.left + slot.width);
266-
}
267-
const minOffset = minLeft - dragged.left;
268-
const maxOffset = maxRight - dragged.width - dragged.left;
269-
return Math.min(maxOffset, Math.max(minOffset, offset));
243+
return clampDragOffset(
244+
slots.map((slot) => ({ id: slot.id, start: slot.left, size: slot.width })),
245+
draggedId,
246+
offset,
247+
);
270248
}
271249

272-
export const TAB_AUTO_SCROLL_EDGE_PX = 40;
273-
export const TAB_AUTO_SCROLL_MAX_STEP_PX = 12;
250+
export const TAB_AUTO_SCROLL_EDGE_PX = REORDER_AUTO_SCROLL_EDGE_PX;
251+
export const TAB_AUTO_SCROLL_MAX_STEP_PX = REORDER_AUTO_SCROLL_MAX_STEP_PX;
274252

275253
// Per-frame auto-scroll velocity while dragging: zero in the middle of the
276254
// strip, ramping up with pointer depth into either edge zone so the scroll
@@ -280,43 +258,11 @@ export function computeTabAutoScrollVelocity(
280258
containerRight: number,
281259
clientX: number,
282260
) {
283-
const edge = Math.min(TAB_AUTO_SCROLL_EDGE_PX, Math.max(8, (containerRight - containerLeft) / 4));
284-
if (clientX < containerLeft + edge) {
285-
const depth = Math.min(1, (containerLeft + edge - clientX) / edge);
286-
return -(1 + depth * (TAB_AUTO_SCROLL_MAX_STEP_PX - 1));
287-
}
288-
if (clientX > containerRight - edge) {
289-
const depth = Math.min(1, (clientX - (containerRight - edge)) / edge);
290-
return 1 + depth * (TAB_AUTO_SCROLL_MAX_STEP_PX - 1);
291-
}
292-
return 0;
261+
return computeDragAutoScrollVelocity(containerLeft, containerRight, clientX);
293262
}
294263

295264
export function reorderTabIdsByKeyboard(tabIds: readonly string[], tabId: string, key: string) {
296-
const currentIndex = tabIds.indexOf(tabId);
297-
if (currentIndex < 0) return null;
298-
299-
let targetIndex = currentIndex;
300-
if (key === "ArrowLeft") {
301-
targetIndex = currentIndex - 1;
302-
} else if (key === "ArrowRight") {
303-
targetIndex = currentIndex + 1;
304-
} else if (key === "Home") {
305-
targetIndex = 0;
306-
} else if (key === "End") {
307-
targetIndex = tabIds.length - 1;
308-
} else {
309-
return null;
310-
}
311-
312-
targetIndex = Math.max(0, Math.min(tabIds.length - 1, targetIndex));
313-
if (targetIndex === currentIndex) return null;
314-
315-
const nextTabIds = [...tabIds];
316-
const [movedTabId] = nextTabIds.splice(currentIndex, 1);
317-
if (!movedTabId) return null;
318-
nextTabIds.splice(targetIndex, 0, movedTabId);
319-
return nextTabIds;
265+
return reorderIdsByKeyboard(tabIds, tabId, key, "horizontal");
320266
}
321267

322268
export function rightDockSingletonTabId(kind: RightDockSingletonTabKind) {

0 commit comments

Comments
 (0)