Refactor UI, settings, and code quality across all categories
- Fix Replace Cover: routes now read preview_path from form POST instead of session (session writes from background threads were lost) - Fix batch generation: submit all jobs immediately, poll all in parallel via Promise.all - Fix label NameError in character generate route - Fix style detail missing characters context - Selected Preview pane: click any image to select it; data-preview-path on all images across all 8 detail templates - Gallery → Library rename across all index page headings and navbar - Settings: add configurable LoRA/checkpoint directories; default checkpoint selector moved from navbar to settings page - Consolidate 6 get_available_*_loras() into single get_available_loras(category) reading from Settings - ComfyUI tooltip shows currently loaded checkpoint name - Remove navbar checkpoint bar - Phase 4 cleanup: remove dead _queue_generation(), add session.modified, standardize log prefixes, rename action_type → action Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
<div class="vr mx-1 d-none d-lg-block"></div>
|
||||
<a href="/create" class="btn btn-sm btn-outline-success">+ Character</a>
|
||||
<a href="/generator" class="btn btn-sm btn-outline-light">Generator</a>
|
||||
<a href="/gallery" class="btn btn-sm btn-outline-light">Gallery</a>
|
||||
<a href="/gallery" class="btn btn-sm btn-outline-light">Image Gallery</a>
|
||||
<a href="/settings" class="btn btn-sm btn-outline-light">Settings</a>
|
||||
<div class="vr mx-1 d-none d-lg-block"></div>
|
||||
<!-- Queue indicator -->
|
||||
@@ -48,19 +48,6 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="default-checkpoint-bar border-bottom mb-4">
|
||||
<div class="container d-flex align-items-center gap-2 py-2">
|
||||
<small class="text-muted text-nowrap">Default checkpoint:</small>
|
||||
<select id="defaultCheckpointSelect" class="form-select form-select-sm" style="max-width: 320px;">
|
||||
<option value="">— workflow default —</option>
|
||||
{% for ckpt in all_checkpoints %}
|
||||
<option value="{{ ckpt.checkpoint_path }}"{% if ckpt.checkpoint_path == default_checkpoint_path %} selected{% endif %}>{{ ckpt.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<small id="checkpointSaveStatus" class="text-muted" style="opacity:0;transition:opacity 0.5s">Saved</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
@@ -129,22 +116,44 @@
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => new bootstrap.Tooltip(el));
|
||||
|
||||
const ckptSelect = document.getElementById('defaultCheckpointSelect');
|
||||
const saveStatus = document.getElementById('checkpointSaveStatus');
|
||||
if (ckptSelect) {
|
||||
ckptSelect.addEventListener('change', () => {
|
||||
fetch('/set_default_checkpoint', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
body: 'checkpoint_path=' + encodeURIComponent(ckptSelect.value)
|
||||
}).then(() => {
|
||||
saveStatus.style.opacity = '1';
|
||||
setTimeout(() => { saveStatus.style.opacity = '0'; }, 1500);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ---- Loaded checkpoint → ComfyUI tooltip ----
|
||||
(function() {
|
||||
let _loadedCheckpoint = null;
|
||||
async function pollLoadedCheckpoint() {
|
||||
try {
|
||||
const r = await fetch('/api/comfyui/loaded_checkpoint', { cache: 'no-store' });
|
||||
const data = await r.json();
|
||||
_loadedCheckpoint = data.checkpoint || null;
|
||||
} catch {
|
||||
_loadedCheckpoint = null;
|
||||
}
|
||||
updateComfyTooltip();
|
||||
}
|
||||
function updateComfyTooltip() {
|
||||
const el = document.getElementById('status-comfyui');
|
||||
if (!el) return;
|
||||
const dot = el.querySelector('.status-dot');
|
||||
const online = dot && dot.classList.contains('status-ok');
|
||||
let text = 'ComfyUI: ' + (online ? 'online' : 'offline');
|
||||
if (_loadedCheckpoint) {
|
||||
const parts = _loadedCheckpoint.split(/[/\\]/);
|
||||
const name = parts[parts.length - 1].replace(/\.safetensors$/, '');
|
||||
text += '\n' + name;
|
||||
}
|
||||
el.setAttribute('data-bs-title', text);
|
||||
el.setAttribute('title', text);
|
||||
const tip = bootstrap.Tooltip.getInstance(el);
|
||||
if (tip) tip.setContent({ '.tooltip-inner': text });
|
||||
}
|
||||
// Hook into the existing status polling to refresh tooltip after status changes
|
||||
window._updateComfyTooltip = updateComfyTooltip;
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
pollLoadedCheckpoint();
|
||||
setInterval(pollLoadedCheckpoint, 30000);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
// ---- Resource delete modal (category galleries) ----
|
||||
@@ -340,14 +349,15 @@
|
||||
if (!el) return;
|
||||
const dot = el.querySelector('.status-dot');
|
||||
dot.className = 'status-dot ' + (ok ? 'status-ok' : 'status-error');
|
||||
if (id === 'status-comfyui' && window._updateComfyTooltip) {
|
||||
window._updateComfyTooltip();
|
||||
return;
|
||||
}
|
||||
const tooltipText = label + ': ' + (ok ? 'online' : 'offline');
|
||||
el.setAttribute('data-bs-title', tooltipText);
|
||||
el.setAttribute('title', tooltipText);
|
||||
// Refresh tooltip instance if already initialised
|
||||
const tip = bootstrap.Tooltip.getInstance(el);
|
||||
if (tip) {
|
||||
tip.setContent({ '.tooltip-inner': tooltipText });
|
||||
}
|
||||
if (tip) tip.setContent({ '.tooltip-inner': tooltipText });
|
||||
}
|
||||
|
||||
async function pollService(svc) {
|
||||
|
||||
Reference in New Issue
Block a user