mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-06-24 20:11:17 -03:00
feat(vlm): sort versions by newest first in VLM view, with disabled sort dropdown
When viewing all versions of a model (VLM mode via 'x versions' button): - Backend always sorts by version ID descending, ignoring current sort_by - A temporary 'Newest version first' option is injected into the sort dropdown (removed on exit, not a permanent option) - The sort dropdown is disabled (greyed out) while VLM is active - On clearing VLM, the previous sort preference is restored and the dropdown re-enabled - Handles stale VLM state (e.g. after page reload with leftover session) - Covers all three model page types: loras, checkpoints, embeddings Also fixes review nits: - Correct i18n call pattern (defaultValue in options object) - Shared _restoreSortAfterVlm() helper to avoid triple duplication
This commit is contained in:
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "Wenigste",
|
||||
"versionsCount": "Lokale Versionen",
|
||||
"versionsCountDesc": "Meiste Versionen zuerst",
|
||||
"versionsCountAsc": "Wenigste Versionen zuerst"
|
||||
"versionsCountAsc": "Wenigste Versionen zuerst",
|
||||
"versionIdDesc": "Neueste Version zuerst"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "Modelliste aktualisieren",
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "Least",
|
||||
"versionsCount": "Local Versions",
|
||||
"versionsCountDesc": "Most versions first",
|
||||
"versionsCountAsc": "Fewest versions first"
|
||||
"versionsCountAsc": "Fewest versions first",
|
||||
"versionIdDesc": "Newest version first"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "Refresh model list",
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "Menos",
|
||||
"versionsCount": "Versiones locales",
|
||||
"versionsCountDesc": "Más versiones primero",
|
||||
"versionsCountAsc": "Menos versiones primero"
|
||||
"versionsCountAsc": "Menos versiones primero",
|
||||
"versionIdDesc": "Versión más nueva primero"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "Actualizar lista de modelos",
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "Moins",
|
||||
"versionsCount": "Versions locales",
|
||||
"versionsCountDesc": "Plus de versions d'abord",
|
||||
"versionsCountAsc": "Moins de versions d'abord"
|
||||
"versionsCountAsc": "Moins de versions d'abord",
|
||||
"versionIdDesc": "Version la plus récente d'abord"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "Actualiser la liste des modèles",
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "הכי פחות",
|
||||
"versionsCount": "גרסאות מקומיות",
|
||||
"versionsCountDesc": "הכי הרבה גרסאות ראשונות",
|
||||
"versionsCountAsc": "הכי מעט גרסאות ראשונות"
|
||||
"versionsCountAsc": "הכי מעט גרסאות ראשונות",
|
||||
"versionIdDesc": "גרסה חדשה ביותר ראשונה"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "רענן רשימת מודלים",
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "少ない",
|
||||
"versionsCount": "ローカルバージョン数",
|
||||
"versionsCountDesc": "バージョン数の多い順",
|
||||
"versionsCountAsc": "バージョン数の少ない順"
|
||||
"versionsCountAsc": "バージョン数の少ない順",
|
||||
"versionIdDesc": "最新バージョン順"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "モデルリストを更新",
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "적은 순",
|
||||
"versionsCount": "로컬 버전 수",
|
||||
"versionsCountDesc": "버전 수 많은 순",
|
||||
"versionsCountAsc": "버전 수 적은 순"
|
||||
"versionsCountAsc": "버전 수 적은 순",
|
||||
"versionIdDesc": "최신 버전순"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "모델 목록 새로고침",
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "Меньше",
|
||||
"versionsCount": "Локальные версии",
|
||||
"versionsCountDesc": "Сначала больше версий",
|
||||
"versionsCountAsc": "Сначала меньше версий"
|
||||
"versionsCountAsc": "Сначала меньше версий",
|
||||
"versionIdDesc": "Сначала новые версии"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "Обновить список моделей",
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "最少",
|
||||
"versionsCount": "本地版本数",
|
||||
"versionsCountDesc": "版本数从多到少",
|
||||
"versionsCountAsc": "版本数从少到多"
|
||||
"versionsCountAsc": "版本数从少到多",
|
||||
"versionIdDesc": "最新版本优先"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "刷新模型列表",
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
"usageAsc": "最少",
|
||||
"versionsCount": "本地版本數",
|
||||
"versionsCountDesc": "版本數從多到少",
|
||||
"versionsCountAsc": "版本數從少到多"
|
||||
"versionsCountAsc": "版本數從少到多",
|
||||
"versionIdDesc": "最新版本優先"
|
||||
},
|
||||
"refresh": {
|
||||
"title": "重新整理模型列表",
|
||||
|
||||
@@ -111,6 +111,12 @@ class BaseModelService(ABC):
|
||||
item for item in sorted_data
|
||||
if self._extract_model_id(item) == civitai_model_id
|
||||
]
|
||||
# VLM mode: always sort by version ID descending (newest version first),
|
||||
# regardless of the current sort_by preference.
|
||||
sorted_data.sort(
|
||||
key=lambda x: self._extract_version_id(x) or 0,
|
||||
reverse=True,
|
||||
)
|
||||
|
||||
# Optionally group by civitai modelId, showing only the latest version per model
|
||||
dedup_lost = 0
|
||||
|
||||
@@ -264,6 +264,23 @@
|
||||
box-shadow: 0 0 0 2px oklch(var(--lora-accent) / 0.15);
|
||||
}
|
||||
|
||||
/* Disabled sort dropdown — used when VLM custom filter is active */
|
||||
.control-group select:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
background-color: var(--bg-color);
|
||||
border-color: var(--border-color);
|
||||
box-shadow: none;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.control-group select:disabled:hover {
|
||||
border-color: var(--border-color);
|
||||
background-color: var(--bg-color);
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Ensure hidden class works properly */
|
||||
.hidden {
|
||||
display: none !important;
|
||||
|
||||
@@ -102,6 +102,7 @@ export class CheckpointsControls extends PageControls {
|
||||
removeSessionItem('vlm_model_name');
|
||||
removeSessionItem('vlm_base_model');
|
||||
removeSessionItem('vlm_page_type');
|
||||
this._restoreSortAfterVlm();
|
||||
// Hide the indicator
|
||||
const indicator = document.getElementById('customFilterIndicator');
|
||||
if (indicator) {
|
||||
|
||||
@@ -119,6 +119,7 @@ export class LorasControls extends PageControls {
|
||||
removeSessionItem('vlm_model_name');
|
||||
removeSessionItem('vlm_base_model');
|
||||
removeSessionItem('vlm_page_type');
|
||||
this._restoreSortAfterVlm();
|
||||
const indicator = document.getElementById('customFilterIndicator');
|
||||
if (indicator) {
|
||||
indicator.classList.add('hidden');
|
||||
|
||||
@@ -465,6 +465,60 @@ export class PageControls {
|
||||
/**
|
||||
* Clear custom filter
|
||||
*/
|
||||
/**
|
||||
* Dynamically add the VLM sort option (version_id:desc) to the sort dropdown.
|
||||
* It is not a permanent option — only present while VLM is active.
|
||||
*/
|
||||
_addVlmSortOption() {
|
||||
const sortSelect = document.getElementById('sortSelect');
|
||||
if (!sortSelect) return;
|
||||
// Only add if not already present
|
||||
if (sortSelect.querySelector('option[value="version_id:desc"]')) return;
|
||||
const opt = document.createElement('option');
|
||||
opt.value = 'version_id:desc';
|
||||
opt.textContent = this._t('loras.controls.sort.versionIdDesc', 'Newest version first');
|
||||
sortSelect.appendChild(opt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the VLM sort option from the sort dropdown.
|
||||
*/
|
||||
_removeVlmSortOption() {
|
||||
const sortSelect = document.getElementById('sortSelect');
|
||||
if (!sortSelect) return;
|
||||
const opt = sortSelect.querySelector('option[value="version_id:desc"]');
|
||||
if (opt) opt.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a translation key via the global i18n helper, falling back to
|
||||
* a plain-text default when the key is missing or i18n is unavailable.
|
||||
*/
|
||||
_t(key, fallback) {
|
||||
if (typeof window.i18n?.t === 'function') {
|
||||
return window.i18n.t(key, { defaultValue: fallback });
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the sort dropdown state after VLM is cleared.
|
||||
* Shared by PageControls.clearCustomFilter() and subclass overrides.
|
||||
*/
|
||||
_restoreSortAfterVlm() {
|
||||
const prevSort = getSessionItem('vlm_prev_sort');
|
||||
removeSessionItem('vlm_prev_sort');
|
||||
const restoredSort = prevSort || 'name:asc';
|
||||
this.pageState.sortBy = restoredSort;
|
||||
this.saveSortPreference(restoredSort);
|
||||
this._removeVlmSortOption();
|
||||
const sortSelect = document.getElementById('sortSelect');
|
||||
if (sortSelect) {
|
||||
sortSelect.value = restoredSort;
|
||||
sortSelect.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger View Local Versions without page reload
|
||||
* Sets sessionStorage and reloads data via the API.
|
||||
@@ -479,6 +533,17 @@ export class PageControls {
|
||||
} else {
|
||||
removeSessionItem('vlm_base_model');
|
||||
}
|
||||
// Save current sort preference so it can be restored when VLM is cleared
|
||||
setSessionItem('vlm_prev_sort', this.pageState.sortBy);
|
||||
// Inject the temporary sort option and force version_id:desc
|
||||
this._addVlmSortOption();
|
||||
this.pageState.sortBy = 'version_id:desc';
|
||||
this.saveSortPreference('version_id:desc');
|
||||
const sortSelect = document.getElementById('sortSelect');
|
||||
if (sortSelect) {
|
||||
sortSelect.value = 'version_id:desc';
|
||||
sortSelect.disabled = true;
|
||||
}
|
||||
// Reload data via API (no page reload)
|
||||
this.resetAndReload(true).then(() => {
|
||||
// Show the VLM indicator after data loads
|
||||
@@ -533,6 +598,7 @@ export class PageControls {
|
||||
checkVlmFilter() {
|
||||
const vlmModelId = getSessionItem('vlm_model_id');
|
||||
const vlmPageType = getSessionItem('vlm_page_type');
|
||||
const sortSelect = document.getElementById('sortSelect');
|
||||
|
||||
// Only show VLM indicator when it belongs to the current page type
|
||||
if (vlmModelId && vlmPageType !== this.pageType) {
|
||||
@@ -541,6 +607,9 @@ export class PageControls {
|
||||
removeSessionItem('vlm_model_name');
|
||||
removeSessionItem('vlm_base_model');
|
||||
removeSessionItem('vlm_page_type');
|
||||
removeSessionItem('vlm_prev_sort');
|
||||
this._removeVlmSortOption();
|
||||
if (sortSelect) sortSelect.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -548,6 +617,13 @@ export class PageControls {
|
||||
const vlmBaseModel = getSessionItem('vlm_base_model');
|
||||
|
||||
if (vlmModelId && vlmModelName) {
|
||||
// VLM is active — inject sort option, disable dropdown, show indicator
|
||||
this._addVlmSortOption();
|
||||
if (sortSelect) {
|
||||
sortSelect.value = 'version_id:desc';
|
||||
sortSelect.disabled = true;
|
||||
}
|
||||
|
||||
const indicator = document.getElementById('customFilterIndicator');
|
||||
const filterText = indicator?.querySelector('.customFilterText');
|
||||
|
||||
@@ -562,6 +638,10 @@ export class PageControls {
|
||||
filterText.textContent = this._truncateText(displayText, 40);
|
||||
filterText.setAttribute('title', displayText);
|
||||
}
|
||||
} else {
|
||||
// No VLM — ensure sort option is removed and dropdown is enabled
|
||||
this._removeVlmSortOption();
|
||||
if (sortSelect) sortSelect.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,6 +657,8 @@ export class PageControls {
|
||||
removeSessionItem('vlm_base_model');
|
||||
removeSessionItem('vlm_page_type');
|
||||
|
||||
this._restoreSortAfterVlm();
|
||||
|
||||
// Hide the indicator
|
||||
const indicator = document.getElementById('customFilterIndicator');
|
||||
if (indicator) {
|
||||
|
||||
Reference in New Issue
Block a user