feat(frontend): add Other Models page with subtype filter and badges

This commit is contained in:
Will Miao
2026-09-12 11:25:51 +08:00
parent 27da7b3ca3
commit fa7ce725c1
45 changed files with 988 additions and 30 deletions
+4 -2
View File
@@ -424,12 +424,13 @@ class BannerService {
/**
* Get the current page type from the URL
* @returns {string} Page type (loras, checkpoints, embeddings, recipes)
* @returns {string} Page type (loras, checkpoints, embeddings, other, recipes)
*/
getCurrentPageType() {
const path = window.location.pathname;
if (path.includes('/checkpoints')) return 'checkpoints';
if (path.includes('/embeddings')) return 'embeddings';
if (path.includes('/other')) return 'other';
if (path.includes('/recipes')) return 'recipes';
return 'loras';
}
@@ -443,7 +444,8 @@ class BannerService {
const endpoints = {
'loras': '/api/lm/loras/reload?rebuild=true',
'checkpoints': '/api/lm/checkpoints/reload?rebuild=true',
'embeddings': '/api/lm/embeddings/reload?rebuild=true'
'embeddings': '/api/lm/embeddings/reload?rebuild=true',
'other': '/api/lm/other/reload?rebuild=true'
};
return endpoints[pageType] || endpoints['loras'];
}
+14
View File
@@ -93,6 +93,20 @@ export class BulkManager {
setFavorite: true,
unfavorite: true
},
[MODEL_TYPES.OTHER]: {
addTags: true,
sendToWorkflow: false,
copyAll: false,
refreshAll: true,
checkUpdates: true,
moveAll: true,
autoOrganize: true,
deleteAll: true,
setContentRating: true,
skipMetadataRefresh: true,
setFavorite: true,
unfavorite: true
},
recipes: {
addTags: true,
sendToWorkflow: false,
+2 -2
View File
@@ -805,7 +805,7 @@ export class FilterManager {
// Call the appropriate manager's load method based on page type
if (this.currentPage === 'recipes' && window.recipeManager) {
await window.recipeManager.loadRecipes(true);
} else if (this.currentPage === 'loras' || this.currentPage === 'embeddings' || this.currentPage === 'checkpoints') {
} else if (this.currentPage === 'loras' || this.currentPage === 'embeddings' || this.currentPage === 'checkpoints' || this.currentPage === 'other') {
// For models page, reset the page and reload
await getModelApiClient().loadMoreWithVirtualScroll(true, false);
}
@@ -904,7 +904,7 @@ export class FilterManager {
// Reload data using the appropriate method for the current page
if (this.currentPage === 'recipes' && window.recipeManager) {
await window.recipeManager.loadRecipes(true);
} else if (this.currentPage === 'loras' || this.currentPage === 'checkpoints' || this.currentPage === 'embeddings') {
} else if (this.currentPage === 'loras' || this.currentPage === 'checkpoints' || this.currentPage === 'embeddings' || this.currentPage === 'other') {
await getModelApiClient().loadMoreWithVirtualScroll(true, true);
}
+6 -8
View File
@@ -60,7 +60,6 @@ class MoveManager {
this.bulkFilePaths = null;
const apiClient = this._getApiClient(modelType);
const currentPageType = state.currentPageType;
const modelConfig = apiClient.apiConfig.config;
// Handle bulk mode
@@ -113,7 +112,7 @@ class MoveManager {
).join('');
// Set default root if available
const settingsKey = `default_${currentPageType.slice(0, -1)}_root`;
const settingsKey = `default_${modelConfig.singularName}_root`;
const defaultRoot = state.global.settings[settingsKey];
if (defaultRoot && rootsData.roots.includes(defaultRoot)) {
modelRootSelect.value = defaultRoot;
@@ -228,13 +227,12 @@ class MoveManager {
if (modelRoot) {
if (this.useDefaultPath) {
// Show actual template path
try {
const singularType = apiClient.modelType.replace(/s$/, '');
const templates = state.global.settings.download_path_templates;
const template = templates[singularType];
const singularType = config.singularName || apiClient.modelType.replace(/s$/, '');
const templates = state.global.settings.download_path_templates;
const template = templates[singularType];
if (template) {
fullPath += `/${template}`;
} catch (error) {
console.error('Failed to fetch template:', error);
} else {
fullPath += '/' + translate('modals.download.autoOrganizedPath');
}
} else {
+2 -2
View File
@@ -298,7 +298,7 @@ export class SearchManager {
pageState.searchOptions.loraName = options.loraName || false;
pageState.searchOptions.loraModel = options.loraModel || false;
pageState.searchOptions.prompt = options.prompt || false;
} else if (this.currentPage === 'loras' || this.currentPage === 'checkpoints' || this.currentPage === 'embeddings') {
} else if (this.currentPage === 'loras' || this.currentPage === 'checkpoints' || this.currentPage === 'embeddings' || this.currentPage === 'other') {
// Update only the relevant fields in searchOptions instead of replacing the whole object
pageState.searchOptions.filename = options.filename || false;
pageState.searchOptions.modelname = options.modelname || false;
@@ -311,7 +311,7 @@ export class SearchManager {
// Call the appropriate manager's load method based on page type
if (this.currentPage === 'recipes' && window.recipeManager) {
window.recipeManager.loadRecipes(true);
} else if (this.currentPage === 'loras' || this.currentPage === 'embeddings' || this.currentPage === 'checkpoints') {
} else if (this.currentPage === 'loras' || this.currentPage === 'embeddings' || this.currentPage === 'checkpoints' || this.currentPage === 'other') {
// For models page, reset the page and reload
getModelApiClient().loadMoreWithVirtualScroll(true, false);
}
+3
View File
@@ -3360,6 +3360,9 @@ export class SettingsManager {
} else if (this.currentPage === 'embeddings') {
// Reload the embeddings without updating folders
await resetAndReload(false);
} else if (this.currentPage === 'other') {
// Reload the other models without updating folders
await resetAndReload(false);
}
}