|
227 | 227 | </Button> |
228 | 228 | </div> |
229 | 229 | </div> |
230 | | - <div v-else-if="isModelItem(item)" class="bg-card"> |
| 230 | + <div v-else-if="isModelItem(item)" :key="item.id" class="bg-card"> |
231 | 231 | <ModelConfigItem |
| 232 | + :key="item.id" |
232 | 233 | :model-name="item.model.name" |
233 | 234 | :model-id="item.model.id" |
234 | 235 | :provider-id="item.providerId" |
@@ -458,15 +459,77 @@ const matchesAdvancedFilters = (model: RENDERER_MODEL_META) => { |
458 | 459 |
|
459 | 460 | const statusSortWeight = (model: RENDERER_MODEL_META) => (model.enabled ? 0 : 1) |
460 | 461 |
|
| 462 | +const getModelKey = (model: RENDERER_MODEL_META) => `${model.providerId}:${model.id}` |
| 463 | +const statusSortOrder = ref<Record<string, number>>({}) |
| 464 | +
|
| 465 | +const buildStatusSortOrder = () => { |
| 466 | + const models = [ |
| 467 | + ...props.customModels, |
| 468 | + ...props.providerModels.flatMap((provider) => provider.models) |
| 469 | + ] |
| 470 | + const nextOrder: Record<string, number> = {} |
| 471 | + const orderedModels = [...models].sort((left, right) => { |
| 472 | + const statusDifference = statusSortWeight(left) - statusSortWeight(right) |
| 473 | + if (statusDifference !== 0) { |
| 474 | + return statusDifference |
| 475 | + } |
| 476 | +
|
| 477 | + return modelNameCollator.compare(left.name, right.name) |
| 478 | + }) |
| 479 | +
|
| 480 | + orderedModels.forEach((model, index) => { |
| 481 | + nextOrder[getModelKey(model)] = index |
| 482 | + }) |
| 483 | +
|
| 484 | + statusSortOrder.value = nextOrder |
| 485 | +} |
| 486 | +
|
| 487 | +const modelStructureSignature = computed(() => |
| 488 | + JSON.stringify({ |
| 489 | + customModels: props.customModels.map((model) => ({ |
| 490 | + providerId: model.providerId, |
| 491 | + id: model.id, |
| 492 | + name: model.name, |
| 493 | + group: model.group, |
| 494 | + type: model.type ?? ModelType.Chat, |
| 495 | + capabilities: getModelCapabilityValues(model) |
| 496 | + })), |
| 497 | + providerModels: props.providerModels.map((provider) => ({ |
| 498 | + providerId: provider.providerId, |
| 499 | + models: provider.models.map((model) => ({ |
| 500 | + id: model.id, |
| 501 | + name: model.name, |
| 502 | + group: model.group, |
| 503 | + type: model.type ?? ModelType.Chat, |
| 504 | + capabilities: getModelCapabilityValues(model) |
| 505 | + })) |
| 506 | + })) |
| 507 | + }) |
| 508 | +) |
| 509 | +
|
| 510 | +watch(modelStructureSignature, buildStatusSortOrder, { immediate: true }) |
| 511 | +
|
461 | 512 | const sortModels = (models: RENDERER_MODEL_META[]) => |
462 | 513 | [...models].sort((left, right) => { |
463 | 514 | if (filterState.sort === 'name') { |
464 | 515 | return modelNameCollator.compare(left.name, right.name) |
465 | 516 | } |
466 | 517 |
|
467 | | - const statusDifference = statusSortWeight(left) - statusSortWeight(right) |
468 | | - if (statusDifference !== 0) { |
469 | | - return statusDifference |
| 518 | + const leftRank = statusSortOrder.value[getModelKey(left)] |
| 519 | + const rightRank = statusSortOrder.value[getModelKey(right)] |
| 520 | +
|
| 521 | + if (leftRank !== undefined || rightRank !== undefined) { |
| 522 | + if (leftRank === undefined) { |
| 523 | + return 1 |
| 524 | + } |
| 525 | +
|
| 526 | + if (rightRank === undefined) { |
| 527 | + return -1 |
| 528 | + } |
| 529 | +
|
| 530 | + if (leftRank !== rightRank) { |
| 531 | + return leftRank - rightRank |
| 532 | + } |
470 | 533 | } |
471 | 534 |
|
472 | 535 | return modelNameCollator.compare(left.name, right.name) |
@@ -634,6 +697,9 @@ const removeFilterToken = (token: FilterToken) => { |
634 | 697 | } |
635 | 698 |
|
636 | 699 | const setSort = (sort: ModelSortKey) => { |
| 700 | + if (sort === 'status') { |
| 701 | + buildStatusSortOrder() |
| 702 | + } |
637 | 703 | filterState.sort = sort |
638 | 704 | sortPopoverOpen.value = false |
639 | 705 | } |
|
0 commit comments