Various UI fixes in config state tab
This commit is contained in:
parent
f22d0dde4e
commit
f3320b802c
1
.gitignore
vendored
1
.gitignore
vendored
@ -33,3 +33,4 @@ notification.mp3
|
|||||||
/test/stdout.txt
|
/test/stdout.txt
|
||||||
/test/stderr.txt
|
/test/stderr.txt
|
||||||
/cache.json
|
/cache.json
|
||||||
|
/config_states/
|
||||||
|
@ -50,7 +50,7 @@ function install_extension_from_index(button, url){
|
|||||||
|
|
||||||
function config_state_confirm_restore(_, config_state_name, config_restore_type) {
|
function config_state_confirm_restore(_, config_state_name, config_restore_type) {
|
||||||
if (config_state_name == "Current") {
|
if (config_state_name == "Current") {
|
||||||
return [false, config_state_name];
|
return [false, config_state_name, config_restore_type];
|
||||||
}
|
}
|
||||||
let restored = "";
|
let restored = "";
|
||||||
if (config_restore_type == "extensions") {
|
if (config_restore_type == "extensions") {
|
||||||
@ -60,6 +60,12 @@ function config_state_confirm_restore(_, config_state_name, config_restore_type)
|
|||||||
} else {
|
} else {
|
||||||
restored = "the webui version and all saved extension versions";
|
restored = "the webui version and all saved extension versions";
|
||||||
}
|
}
|
||||||
let confirmed = confirm("Are you sure you want to restore from this state?\nThis will reset " + restored + ".\n(A backup of the current state will be made.)");
|
let confirmed = confirm("Are you sure you want to restore from this state?\nThis will reset " + restored + ".");
|
||||||
|
if (confirmed) {
|
||||||
|
restart_reload();
|
||||||
|
gradioApp().querySelectorAll('#extensions .extension_status').forEach(function(x){
|
||||||
|
x.innerHTML = "Loading..."
|
||||||
|
})
|
||||||
|
}
|
||||||
return [confirmed, config_state_name, config_restore_type];
|
return [confirmed, config_state_name, config_restore_type];
|
||||||
}
|
}
|
||||||
|
200
modules/config_states.py
Normal file
200
modules/config_states.py
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
"""
|
||||||
|
Supports saving and restoring webui and extensions from a known working set of commits
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import tqdm
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from collections import OrderedDict
|
||||||
|
import git
|
||||||
|
|
||||||
|
from modules import shared, extensions
|
||||||
|
from modules.paths_internal import extensions_dir, extensions_builtin_dir, script_path, config_states_dir
|
||||||
|
|
||||||
|
|
||||||
|
all_config_states = OrderedDict()
|
||||||
|
|
||||||
|
|
||||||
|
def list_config_states():
|
||||||
|
global all_config_states
|
||||||
|
|
||||||
|
all_config_states.clear()
|
||||||
|
os.makedirs(config_states_dir, exist_ok=True)
|
||||||
|
|
||||||
|
config_states = []
|
||||||
|
for filename in os.listdir(config_states_dir):
|
||||||
|
if filename.endswith(".json"):
|
||||||
|
path = os.path.join(config_states_dir, filename)
|
||||||
|
with open(path, "r", encoding="utf-8") as f:
|
||||||
|
j = json.load(f)
|
||||||
|
j["filepath"] = path
|
||||||
|
config_states.append(j)
|
||||||
|
|
||||||
|
config_states = list(sorted(config_states, key=lambda cs: cs["created_at"], reverse=True))
|
||||||
|
|
||||||
|
for cs in config_states:
|
||||||
|
timestamp = time.asctime(time.gmtime(cs["created_at"]))
|
||||||
|
name = cs.get("name", "Config")
|
||||||
|
full_name = f"{name}: {timestamp}"
|
||||||
|
all_config_states[full_name] = cs
|
||||||
|
|
||||||
|
return all_config_states
|
||||||
|
|
||||||
|
|
||||||
|
def get_webui_config():
|
||||||
|
webui_repo = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.exists(os.path.join(script_path, ".git")):
|
||||||
|
webui_repo = git.Repo(script_path)
|
||||||
|
except Exception:
|
||||||
|
print(f"Error reading webui git info from {script_path}:", file=sys.stderr)
|
||||||
|
print(traceback.format_exc(), file=sys.stderr)
|
||||||
|
|
||||||
|
webui_remote = None
|
||||||
|
webui_commit_hash = None
|
||||||
|
webui_commit_date = None
|
||||||
|
webui_branch = None
|
||||||
|
if webui_repo and not webui_repo.bare:
|
||||||
|
try:
|
||||||
|
webui_remote = next(webui_repo.remote().urls, None)
|
||||||
|
head = webui_repo.head.commit
|
||||||
|
webui_commit_date = webui_repo.head.commit.committed_date
|
||||||
|
webui_commit_hash = head.hexsha
|
||||||
|
webui_branch = webui_repo.active_branch.name
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
webui_remote = None
|
||||||
|
|
||||||
|
return {
|
||||||
|
"remote": webui_remote,
|
||||||
|
"commit_hash": webui_commit_hash,
|
||||||
|
"commit_date": webui_commit_date,
|
||||||
|
"branch": webui_branch,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_extension_config():
|
||||||
|
ext_config = {}
|
||||||
|
|
||||||
|
for ext in extensions.extensions:
|
||||||
|
entry = {
|
||||||
|
"name": ext.name,
|
||||||
|
"path": ext.path,
|
||||||
|
"enabled": ext.enabled,
|
||||||
|
"is_builtin": ext.is_builtin,
|
||||||
|
"remote": ext.remote,
|
||||||
|
"commit_hash": ext.commit_hash,
|
||||||
|
"commit_date": ext.commit_date,
|
||||||
|
"branch": ext.branch,
|
||||||
|
"have_info_from_repo": ext.have_info_from_repo
|
||||||
|
}
|
||||||
|
|
||||||
|
ext_config[ext.name] = entry
|
||||||
|
|
||||||
|
return ext_config
|
||||||
|
|
||||||
|
|
||||||
|
def get_config():
|
||||||
|
creation_time = datetime.now().timestamp()
|
||||||
|
webui_config = get_webui_config()
|
||||||
|
ext_config = get_extension_config()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"created_at": creation_time,
|
||||||
|
"webui": webui_config,
|
||||||
|
"extensions": ext_config
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def restore_webui_config(config):
|
||||||
|
print("* Restoring webui state...")
|
||||||
|
|
||||||
|
if "webui" not in config:
|
||||||
|
print("Error: No webui data saved to config")
|
||||||
|
return
|
||||||
|
|
||||||
|
webui_config = config["webui"]
|
||||||
|
|
||||||
|
if "commit_hash" not in webui_config:
|
||||||
|
print("Error: No commit saved to webui config")
|
||||||
|
return
|
||||||
|
|
||||||
|
webui_commit_hash = webui_config.get("commit_hash", None)
|
||||||
|
webui_repo = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.exists(os.path.join(script_path, ".git")):
|
||||||
|
webui_repo = git.Repo(script_path)
|
||||||
|
except Exception:
|
||||||
|
print(f"Error reading webui git info from {script_path}:", file=sys.stderr)
|
||||||
|
print(traceback.format_exc(), file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
webui_repo.git.fetch(all=True)
|
||||||
|
webui_repo.git.reset(webui_commit_hash, hard=True)
|
||||||
|
print(f"* Restored webui to commit {webui_commit_hash}.")
|
||||||
|
except Exception:
|
||||||
|
print(f"Error restoring webui to commit {webui_commit_hash}:", file=sys.stderr)
|
||||||
|
print(traceback.format_exc(), file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def restore_extension_config(config):
|
||||||
|
print("* Restoring extension state...")
|
||||||
|
|
||||||
|
if "extensions" not in config:
|
||||||
|
print("Error: No extension data saved to config")
|
||||||
|
return
|
||||||
|
|
||||||
|
ext_config = config["extensions"]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
disabled = []
|
||||||
|
|
||||||
|
for ext in tqdm.tqdm(extensions.extensions):
|
||||||
|
if ext.is_builtin:
|
||||||
|
continue
|
||||||
|
|
||||||
|
ext.read_info_from_repo()
|
||||||
|
current_commit = ext.commit_hash
|
||||||
|
|
||||||
|
if ext.name not in ext_config:
|
||||||
|
ext.disabled = True
|
||||||
|
disabled.append(ext.name)
|
||||||
|
results.append((ext, current_commit[:8], False, "Saved extension state not found in config, marking as disabled"))
|
||||||
|
continue
|
||||||
|
|
||||||
|
entry = ext_config[ext.name]
|
||||||
|
|
||||||
|
if "commit_hash" in entry and entry["commit_hash"]:
|
||||||
|
try:
|
||||||
|
ext.fetch_and_reset_hard(entry["commit_hash"])
|
||||||
|
ext.read_info_from_repo()
|
||||||
|
if current_commit != entry["commit_hash"]:
|
||||||
|
results.append((ext, current_commit[:8], True, entry["commit_hash"][:8]))
|
||||||
|
except Exception as ex:
|
||||||
|
results.append((ext, current_commit[:8], False, ex))
|
||||||
|
else:
|
||||||
|
results.append((ext, current_commit[:8], False, "No commit hash found in config"))
|
||||||
|
|
||||||
|
if not entry.get("enabled", False):
|
||||||
|
ext.disabled = True
|
||||||
|
disabled.append(ext.name)
|
||||||
|
else:
|
||||||
|
ext.disabled = False
|
||||||
|
|
||||||
|
shared.opts.disabled_extensions = disabled
|
||||||
|
shared.opts.save(shared.config_filename)
|
||||||
|
|
||||||
|
print("* Finished restoring extensions. Results:")
|
||||||
|
for ext, prev_commit, success, result in results:
|
||||||
|
if success:
|
||||||
|
print(f" + {ext.name}: {prev_commit} -> {result}")
|
||||||
|
else:
|
||||||
|
print(f" ! {ext.name}: FAILURE ({result})")
|
@ -17,6 +17,7 @@ from modules.paths_internal import config_states_dir
|
|||||||
from modules.call_queue import wrap_gradio_gpu_call
|
from modules.call_queue import wrap_gradio_gpu_call
|
||||||
|
|
||||||
available_extensions = {"extensions": []}
|
available_extensions = {"extensions": []}
|
||||||
|
STYLE_PRIMARY = ' style="color: var(--primary-400)"'
|
||||||
|
|
||||||
|
|
||||||
def check_access():
|
def check_access():
|
||||||
@ -67,7 +68,7 @@ def save_config_state(name):
|
|||||||
config_states.list_config_states()
|
config_states.list_config_states()
|
||||||
new_value = next(iter(config_states.all_config_states.keys()), "Current")
|
new_value = next(iter(config_states.all_config_states.keys()), "Current")
|
||||||
new_choices = ["Current"] + list(config_states.all_config_states.keys())
|
new_choices = ["Current"] + list(config_states.all_config_states.keys())
|
||||||
return gr.Dropdown.update(value=new_value, choices=new_choices), f"<span>Saved current webui/extension state to '{filename}'</span>"
|
return gr.Dropdown.update(value=new_value, choices=new_choices), f"<span>Saved current webui/extension state to \"{filename}\"</span>"
|
||||||
|
|
||||||
|
|
||||||
def restore_config_state(confirmed, config_state_name, restore_type):
|
def restore_config_state(confirmed, config_state_name, restore_type):
|
||||||
@ -78,14 +79,12 @@ def restore_config_state(confirmed, config_state_name, restore_type):
|
|||||||
|
|
||||||
check_access()
|
check_access()
|
||||||
|
|
||||||
save_config_state("Backup (pre-restore)")
|
|
||||||
|
|
||||||
config_state = config_states.all_config_states[config_state_name]
|
config_state = config_states.all_config_states[config_state_name]
|
||||||
|
|
||||||
print(f"Restoring webui state from backup: {restore_type}")
|
print(f"*** Restoring webui state from backup: {restore_type} ***")
|
||||||
|
|
||||||
if restore_type == "extensions" or restore_type == "both":
|
if restore_type == "extensions" or restore_type == "both":
|
||||||
shared.opts.restore_config_state_file = config_state["filename"]
|
shared.opts.restore_config_state_file = config_state["filepath"]
|
||||||
shared.opts.save(shared.config_filename)
|
shared.opts.save(shared.config_filename)
|
||||||
|
|
||||||
if restore_type == "webui" or restore_type == "both":
|
if restore_type == "webui" or restore_type == "both":
|
||||||
@ -149,7 +148,7 @@ def extension_table():
|
|||||||
|
|
||||||
style = ""
|
style = ""
|
||||||
if shared.opts.disable_all_extensions == "extra" and not ext.is_builtin or shared.opts.disable_all_extensions == "all":
|
if shared.opts.disable_all_extensions == "extra" and not ext.is_builtin or shared.opts.disable_all_extensions == "all":
|
||||||
style = ' style="color: var(--primary-400)"'
|
style = STYLE_PRIMARY
|
||||||
|
|
||||||
code += f"""
|
code += f"""
|
||||||
<tr>
|
<tr>
|
||||||
@ -181,17 +180,25 @@ def update_config_states_table(state_name):
|
|||||||
|
|
||||||
webui_remote = config_state["webui"]["remote"] or ""
|
webui_remote = config_state["webui"]["remote"] or ""
|
||||||
webui_branch = config_state["webui"]["branch"]
|
webui_branch = config_state["webui"]["branch"]
|
||||||
webui_commit_hash = config_state["webui"]["commit_hash"]
|
webui_commit_hash = config_state["webui"]["commit_hash"] or "<unknown>"
|
||||||
if webui_commit_hash:
|
|
||||||
webui_commit_hash = webui_commit_hash[:8]
|
|
||||||
else:
|
|
||||||
webui_commit_hash = "<unknown>"
|
|
||||||
webui_commit_date = config_state["webui"]["commit_date"]
|
webui_commit_date = config_state["webui"]["commit_date"]
|
||||||
if webui_commit_date:
|
if webui_commit_date:
|
||||||
webui_commit_date = time.asctime(time.gmtime(webui_commit_date))
|
webui_commit_date = time.asctime(time.gmtime(webui_commit_date))
|
||||||
else:
|
else:
|
||||||
webui_commit_date = "<unknown>"
|
webui_commit_date = "<unknown>"
|
||||||
|
|
||||||
|
current_webui = config_states.get_webui_config()
|
||||||
|
|
||||||
|
style_remote = ""
|
||||||
|
style_branch = ""
|
||||||
|
style_commit = ""
|
||||||
|
if current_webui["remote"] != webui_remote:
|
||||||
|
style_remote = STYLE_PRIMARY
|
||||||
|
if current_webui["branch"] != webui_branch:
|
||||||
|
style_branch = STYLE_PRIMARY
|
||||||
|
if current_webui["commit_hash"] != webui_commit_hash:
|
||||||
|
style_commit = STYLE_PRIMARY
|
||||||
|
|
||||||
code += f"""<h2>Config Backup: {config_name}</h2>
|
code += f"""<h2>Config Backup: {config_name}</h2>
|
||||||
<span>Created at: {created_date}</span>"""
|
<span>Created at: {created_date}</span>"""
|
||||||
|
|
||||||
@ -207,10 +214,10 @@ def update_config_states_table(state_name):
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{webui_remote}</td>
|
<td><label{style_remote}>{webui_remote}</label></td>
|
||||||
<td>{webui_branch}</td>
|
<td><label{style_branch}>{webui_branch}</label></td>
|
||||||
<td>{webui_commit_hash}</td>
|
<td><label{style_commit}>{webui_commit_hash[:8]}</label></td>
|
||||||
<td>{webui_commit_date}</td>
|
<td><label{style_commit}>{webui_commit_date}</label></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -253,13 +260,13 @@ def update_config_states_table(state_name):
|
|||||||
current_ext = ext_map[ext_name]
|
current_ext = ext_map[ext_name]
|
||||||
current_ext.read_info_from_repo()
|
current_ext.read_info_from_repo()
|
||||||
if current_ext.enabled != ext_enabled:
|
if current_ext.enabled != ext_enabled:
|
||||||
style_enabled = ' style="color: var(--primary-400)"'
|
style_enabled = STYLE_PRIMARY
|
||||||
if current_ext.remote != ext_remote:
|
if current_ext.remote != ext_remote:
|
||||||
style_remote = ' style="color: var(--primary-400)"'
|
style_remote = STYLE_PRIMARY
|
||||||
if current_ext.branch != ext_branch:
|
if current_ext.branch != ext_branch:
|
||||||
style_branch = ' style="color: var(--primary-400)"'
|
style_branch = STYLE_PRIMARY
|
||||||
if current_ext.commit_hash != ext_commit_hash:
|
if current_ext.commit_hash != ext_commit_hash:
|
||||||
style_commit = ' style="color: var(--primary-400)"'
|
style_commit = STYLE_PRIMARY
|
||||||
|
|
||||||
code += f"""
|
code += f"""
|
||||||
<tr>
|
<tr>
|
||||||
|
8
webui.py
8
webui.py
@ -114,8 +114,10 @@ def initialize():
|
|||||||
print(f"*** About to restore extension state from file: {config_state_file}")
|
print(f"*** About to restore extension state from file: {config_state_file}")
|
||||||
with open(config_state_file, "r", encoding="utf-8") as f:
|
with open(config_state_file, "r", encoding="utf-8") as f:
|
||||||
config_state = json.load(f)
|
config_state = json.load(f)
|
||||||
config_states.restore_extension_state(config_state)
|
config_states.restore_extension_config(config_state)
|
||||||
startup_timer.record("restore extension config")
|
startup_timer.record("restore extension config")
|
||||||
|
else:
|
||||||
|
print(f"!!! Config state backup not found: {config_state_file}")
|
||||||
|
|
||||||
if cmd_opts.ui_debug_mode:
|
if cmd_opts.ui_debug_mode:
|
||||||
shared.sd_upscalers = upscaler.UpscalerLanczos().scalers
|
shared.sd_upscalers = upscaler.UpscalerLanczos().scalers
|
||||||
@ -321,8 +323,10 @@ def webui():
|
|||||||
print(f"*** About to restore extension state from file: {config_state_file}")
|
print(f"*** About to restore extension state from file: {config_state_file}")
|
||||||
with open(config_state_file, "r", encoding="utf-8") as f:
|
with open(config_state_file, "r", encoding="utf-8") as f:
|
||||||
config_state = json.load(f)
|
config_state = json.load(f)
|
||||||
config_states.restore_extension_state(config_state)
|
config_states.restore_extension_config(config_state)
|
||||||
startup_timer.record("restore extension config")
|
startup_timer.record("restore extension config")
|
||||||
|
else:
|
||||||
|
print(f"!!! Config state backup not found: {config_state_file}")
|
||||||
|
|
||||||
localization.list_localizations(cmd_opts.localizations_dir)
|
localization.list_localizations(cmd_opts.localizations_dir)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user