Compare commits

..

2 Commits

Author SHA1 Message Date
Will Miao
2b361f4f5d feat(ui): add group-by-model toggle to global context menu
Adds a 'Group by Model' toggle entry to the right-click global context
menu for quick access, complementing the existing setting in
Settings → Layout Settings. The menu item shows a checkmark indicator
reflecting the current state and immediately reloads the view on toggle.

Also fixes he.json translation that was mojibake (garbled characters).

Includes:
- Context menu HTML item with check-indicator
- JS toggle logic via settingsManager
- i18n for all 10 locales
- Hebrew translation fix
2026-06-22 11:31:15 +08:00
Will Miao
7438072f8c feat(save-image): add %batch_num% support in batch loop 2026-06-22 09:11:38 +08:00
13 changed files with 68 additions and 1 deletions

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "Ausgeschlossene Modelle verwalten"
},
"groupByModel": {
"label": "Nach Modell gruppieren"
}
},
"header": {

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "Manage Excluded Models"
},
"groupByModel": {
"label": "Group by Model"
}
},
"header": {

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "Gestionar modelos excluidos"
},
"groupByModel": {
"label": "Agrupar por modelo"
}
},
"header": {

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "Gérer les modèles exclus"
},
"groupByModel": {
"label": "Grouper par modèle"
}
},
"header": {

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "ניהול מודלים מוחרגים"
},
"groupByModel": {
"label": "קיבוץ לפי דגם"
}
},
"header": {

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "除外モデルを管理"
},
"groupByModel": {
"label": "モデルでグループ化"
}
},
"header": {

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "제외된 모델 관리"
},
"groupByModel": {
"label": "모델별 그룹화"
}
},
"header": {

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "Управление исключёнными моделями"
},
"groupByModel": {
"label": "Группировать по модели"
}
},
"header": {

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "管理已排除的模型"
},
"groupByModel": {
"label": "按模型分组"
}
},
"header": {

View File

@@ -183,6 +183,9 @@
},
"manageExcludedModels": {
"label": "管理已排除的模型"
},
"groupByModel": {
"label": "按模型分組"
}
},
"header": {

View File

@@ -608,7 +608,7 @@ class SaveImageLM:
img = Image.fromarray(np.clip(img, 0, 255).astype(np.uint8))
# Generate filename with counter if needed
base_filename = filename
base_filename = filename.replace("%batch_num%", str(i))
if add_counter_to_filename:
# Use counter + i to ensure unique filenames for all images in batch
current_counter = counter + i

View File

@@ -24,6 +24,14 @@ export class GlobalContextMenu extends BaseContextMenu {
const cleanupExamplesItem = this.menu.querySelector('[data-action="cleanup-example-images-folders"]');
const excludedModelsItem = this.menu.querySelector('[data-action="manage-excluded-models"]');
const repairRecipesItem = this.menu.querySelector('[data-action="repair-recipes"]');
const groupByModelItem = this.menu.querySelector('[data-action="toggle-group-by-model"]');
const groupByModelCheck = groupByModelItem?.querySelector('.check-indicator');
// Update check indicator for group-by-model
if (groupByModelCheck) {
const isEnabled = !!state.global.settings.group_by_model;
groupByModelCheck.style.display = isEnabled ? 'block' : 'none';
}
if (isRecipesPage) {
modelUpdateItem?.classList.add('hidden');
@@ -31,6 +39,7 @@ export class GlobalContextMenu extends BaseContextMenu {
downloadExamplesItem?.classList.add('hidden');
cleanupExamplesItem?.classList.add('hidden');
excludedModelsItem?.classList.add('hidden');
groupByModelItem?.classList.add('hidden');
repairRecipesItem?.classList.remove('hidden');
} else {
modelUpdateItem?.classList.remove('hidden');
@@ -38,6 +47,7 @@ export class GlobalContextMenu extends BaseContextMenu {
downloadExamplesItem?.classList.remove('hidden');
cleanupExamplesItem?.classList.remove('hidden');
excludedModelsItem?.classList.remove('hidden');
groupByModelItem?.classList.remove('hidden');
repairRecipesItem?.classList.add('hidden');
}
@@ -74,6 +84,9 @@ export class GlobalContextMenu extends BaseContextMenu {
case 'manage-excluded-models':
this.manageExcludedModels();
break;
case 'toggle-group-by-model':
this.toggleGroupByModel();
break;
default:
console.warn(`Unhandled global context menu action: ${action}`);
break;
@@ -86,6 +99,25 @@ export class GlobalContextMenu extends BaseContextMenu {
});
}
toggleGroupByModel() {
const sm = window.settingsManager;
if (!sm) {
console.error('settingsManager not available on window');
return;
}
const newValue = !state.global.settings.group_by_model;
state.global.settings.group_by_model = newValue;
sm.saveSetting('group_by_model', newValue).catch((error) => {
console.error('Failed to save group_by_model setting:', error);
// Revert state on failure
state.global.settings.group_by_model = !newValue;
});
sm.applyFrontendSettings();
sm.reloadContent();
}
async downloadExampleImages(menuItem) {
const downloadPath = state?.global?.settings?.example_images_path;
if (!downloadPath) {

View File

@@ -158,6 +158,11 @@
<div class="context-menu-item" data-action="manage-excluded-models">
<i class="fas fa-eye-slash"></i> <span>{{ t('globalContextMenu.manageExcludedModels.label', default='Manage Excluded Models') }}</span>
</div>
<div class="context-menu-separator"></div>
<div class="context-menu-item" data-action="toggle-group-by-model">
<i class="fas fa-layer-group"></i> <span>{{ t('globalContextMenu.groupByModel.label') }}</span>
<i class="fas fa-check check-indicator" style="margin-left:auto;display:none"></i>
</div>
<div class="context-menu-item" data-action="repair-recipes">
<i class="fas fa-tools"></i> <span>{{ t('globalContextMenu.repairRecipes.label') }}</span>
</div>