@@ -353,6 +441,20 @@ function renderEmptyState(container) {
`;
}
+function renderFilteredEmptyState(baseModelLabel) {
+ const message = translate(
+ 'modals.model.versions.filters.empty',
+ { baseModel: baseModelLabel },
+ 'No versions match the current base model filter.'
+ );
+ return `
+
+
+
${escapeHtml(message)}
+
+ `;
+}
+
function renderErrorState(container, message) {
const fallback = translate('modals.model.versions.error', {}, 'Failed to load versions.');
container.innerHTML = `
@@ -391,6 +493,8 @@ export function initVersionsTab({
record: null,
};
+ let displayMode = getDefaultDisplayMode();
+
let apiClient;
function ensureClient() {
@@ -414,55 +518,92 @@ export function initVersionsTab({
`;
}
- function render(record) {
- controller.record = record;
- controller.hasLoaded = true;
+function render(record) {
+ controller.record = record;
+ controller.hasLoaded = true;
- if (!record || !Array.isArray(record.versions) || record.versions.length === 0) {
- renderEmptyState(container);
- return;
- }
-
- const latestLibraryVersionId = getLatestLibraryVersionId(record);
- let dividerInserted = false;
-
- const sortedVersions = [...record.versions].sort(
- (a, b) => Number(b.versionId) - Number(a.versionId)
- );
-
- const rowsMarkup = sortedVersions
- .map(version => {
- const isNewer =
- typeof latestLibraryVersionId === 'number' &&
- version.versionId > latestLibraryVersionId;
- let markup = '';
- if (
- !dividerInserted &&
- typeof latestLibraryVersionId === 'number' &&
- !isNewer
- ) {
- dividerInserted = true;
- markup += '
';
- }
- markup += renderRow(version, {
- latestLibraryVersionId,
- currentVersionId: normalizedCurrentVersionId,
- modelId: record?.modelId ?? modelId,
- });
- return markup;
- })
- .join('');
-
- container.innerHTML = `
- ${renderToolbar(record)}
-
- ${rowsMarkup}
-
- `;
-
- setupMediaHoverInteractions(container);
+ if (!record || !Array.isArray(record.versions) || record.versions.length === 0) {
+ renderEmptyState(container);
+ return;
}
+ const latestLibraryVersionId = getLatestLibraryVersionId(record);
+ const { normalized: currentBaseModelNormalized, raw: currentBaseModelLabel } =
+ getCurrentVersionBaseModel(record, normalizedCurrentVersionId);
+ const isFilteringActive =
+ displayMode === DISPLAY_FILTER_MODES.SAME_BASE &&
+ Boolean(currentBaseModelNormalized);
+
+ const sortedVersions = [...record.versions].sort(
+ (a, b) => Number(b.versionId) - Number(a.versionId)
+ );
+
+ const filteredVersions = sortedVersions.filter(version => {
+ if (!isFilteringActive) {
+ return true;
+ }
+ return normalizeBaseModelName(version.baseModel) === currentBaseModelNormalized;
+ });
+
+ const dividerThresholdVersionId = (() => {
+ if (!isFilteringActive) {
+ return latestLibraryVersionId;
+ }
+ const baseLocalVersionIds = record.versions
+ .filter(
+ version =>
+ version.isInLibrary &&
+ normalizeBaseModelName(version.baseModel) === currentBaseModelNormalized &&
+ typeof version.versionId === 'number'
+ )
+ .map(version => version.versionId);
+ if (!baseLocalVersionIds.length) {
+ return null;
+ }
+ return Math.max(...baseLocalVersionIds);
+ })();
+
+ let dividerInserted = false;
+
+ const rowsMarkup = filteredVersions
+ .map(version => {
+ const isNewer =
+ typeof latestLibraryVersionId === 'number' &&
+ version.versionId > latestLibraryVersionId;
+ let markup = '';
+ if (
+ !dividerInserted &&
+ typeof dividerThresholdVersionId === 'number' &&
+ !(version.versionId > dividerThresholdVersionId)
+ ) {
+ dividerInserted = true;
+ markup += '
';
+ }
+ markup += renderRow(version, {
+ latestLibraryVersionId,
+ currentVersionId: normalizedCurrentVersionId,
+ modelId: record?.modelId ?? modelId,
+ });
+ return markup;
+ })
+ .join('');
+
+ const listContent =
+ rowsMarkup || renderFilteredEmptyState(currentBaseModelLabel);
+
+ container.innerHTML = `
+ ${renderToolbar(record, {
+ displayMode,
+ isFilteringActive,
+ })}
+
+ ${listContent}
+
+ `;
+
+ setupMediaHoverInteractions(container);
+}
+
async function loadVersions({ forceRefresh = false, eager = false } = {}) {
if (controller.isLoading) {
return;
@@ -531,6 +672,17 @@ export function initVersionsTab({
}
}
+ function handleToggleVersionDisplayMode() {
+ displayMode =
+ displayMode === DISPLAY_FILTER_MODES.SAME_BASE
+ ? DISPLAY_FILTER_MODES.ANY
+ : DISPLAY_FILTER_MODES.SAME_BASE;
+ if (!controller.record) {
+ return;
+ }
+ render(controller.record);
+ }
+
async function handleToggleVersionIgnore(button, versionId) {
if (!controller.record) {
return;
@@ -799,9 +951,17 @@ export function initVersionsTab({
const toolbarAction = event.target.closest('[data-versions-action]');
if (toolbarAction) {
const action = toolbarAction.dataset.versionsAction;
- if (action === 'toggle-model-ignore') {
- event.preventDefault();
- await handleToggleModelIgnore(toolbarAction);
+ switch (action) {
+ case 'toggle-model-ignore':
+ event.preventDefault();
+ await handleToggleModelIgnore(toolbarAction);
+ break;
+ case 'toggle-version-display-mode':
+ event.preventDefault();
+ handleToggleVersionDisplayMode();
+ break;
+ default:
+ break;
}
return;
}
diff --git a/static/js/managers/SettingsManager.js b/static/js/managers/SettingsManager.js
index 705afc43..7a6b02ca 100644
--- a/static/js/managers/SettingsManager.js
+++ b/static/js/managers/SettingsManager.js
@@ -412,6 +412,11 @@ export class SettingsManager {
modelNameDisplaySelect.value = state.global.settings.model_name_display || 'model_name';
}
+ const updateFlagStrategySelect = document.getElementById('updateFlagStrategy');
+ if (updateFlagStrategySelect) {
+ updateFlagStrategySelect.value = state.global.settings.update_flag_strategy || 'same_base';
+ }
+
// Set optimize example images setting
const optimizeExampleImagesCheckbox = document.getElementById('optimizeExampleImages');
if (optimizeExampleImagesCheckbox) {
@@ -1334,11 +1339,7 @@ export class SettingsManager {
showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success');
- if (settingKey === 'model_name_display') {
- this.reloadContent();
- }
-
- if (settingKey === 'model_card_footer_action') {
+ if (settingKey === 'model_name_display' || settingKey === 'model_card_footer_action' || settingKey === 'update_flag_strategy') {
this.reloadContent();
}
} catch (error) {
diff --git a/static/js/state/index.js b/static/js/state/index.js
index ee54c066..b8157f66 100644
--- a/static/js/state/index.js
+++ b/static/js/state/index.js
@@ -33,6 +33,7 @@ const DEFAULT_SETTINGS_BASE = Object.freeze({
include_trigger_words: false,
compact_mode: false,
priority_tags: { ...DEFAULT_PRIORITY_TAG_CONFIG },
+ update_flag_strategy: 'same_base',
});
export function createDefaultSettings() {
diff --git a/templates/components/modals/settings_modal.html b/templates/components/modals/settings_modal.html
index 4b40e976..3efcea9a 100644
--- a/templates/components/modals/settings_modal.html
+++ b/templates/components/modals/settings_modal.html
@@ -320,6 +320,27 @@
+
+