Merge pull request #10943 from catboxanon/sort
Allow dynamically sorting extra networks in UI
This commit is contained in:
commit
b1fd2aaa8b
|
@ -13,7 +13,7 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
|
||||||
lora.list_available_loras()
|
lora.list_available_loras()
|
||||||
|
|
||||||
def list_items(self):
|
def list_items(self):
|
||||||
for name, lora_on_disk in lora.available_loras.items():
|
for index, (name, lora_on_disk) in enumerate(lora.available_loras.items()):
|
||||||
path, ext = os.path.splitext(lora_on_disk.filename)
|
path, ext = os.path.splitext(lora_on_disk.filename)
|
||||||
|
|
||||||
alias = lora_on_disk.get_alias()
|
alias = lora_on_disk.get_alias()
|
||||||
|
@ -27,6 +27,8 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
|
||||||
"prompt": json.dumps(f"<lora:{alias}:") + " + opts.extra_networks_default_multiplier + " + json.dumps(">"),
|
"prompt": json.dumps(f"<lora:{alias}:") + " + opts.extra_networks_default_multiplier + " + json.dumps(">"),
|
||||||
"local_preview": f"{path}.{shared.opts.samples_format}",
|
"local_preview": f"{path}.{shared.opts.samples_format}",
|
||||||
"metadata": json.dumps(lora_on_disk.metadata, indent=4) if lora_on_disk.metadata else None,
|
"metadata": json.dumps(lora_on_disk.metadata, indent=4) if lora_on_disk.metadata else None,
|
||||||
|
"sort_keys": {'default': index, **self.get_sort_keys(lora_on_disk.filename)},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def allowed_directories_for_previews(self):
|
def allowed_directories_for_previews(self):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class='card' style={style} onclick={card_clicked}>
|
<div class='card' style={style} onclick={card_clicked} {sort_keys}>
|
||||||
{background_image}
|
{background_image}
|
||||||
{metadata_button}
|
{metadata_button}
|
||||||
<div class='actions'>
|
<div class='actions'>
|
||||||
|
|
|
@ -3,10 +3,17 @@ function setupExtraNetworksForTab(tabname) {
|
||||||
|
|
||||||
var tabs = gradioApp().querySelector('#' + tabname + '_extra_tabs > div');
|
var tabs = gradioApp().querySelector('#' + tabname + '_extra_tabs > div');
|
||||||
var search = gradioApp().querySelector('#' + tabname + '_extra_search textarea');
|
var search = gradioApp().querySelector('#' + tabname + '_extra_search textarea');
|
||||||
|
var sort = gradioApp().getElementById(tabname + '_extra_sort');
|
||||||
|
var sortOrder = gradioApp().getElementById(tabname + '_extra_sortorder');
|
||||||
var refresh = gradioApp().getElementById(tabname + '_extra_refresh');
|
var refresh = gradioApp().getElementById(tabname + '_extra_refresh');
|
||||||
|
|
||||||
search.classList.add('search');
|
search.classList.add('search');
|
||||||
|
sort.classList.add('sort');
|
||||||
|
sortOrder.classList.add('sortorder');
|
||||||
|
sort.dataset.sortkey = 'sortDefault';
|
||||||
tabs.appendChild(search);
|
tabs.appendChild(search);
|
||||||
|
tabs.appendChild(sort);
|
||||||
|
tabs.appendChild(sortOrder);
|
||||||
tabs.appendChild(refresh);
|
tabs.appendChild(refresh);
|
||||||
|
|
||||||
var applyFilter = function() {
|
var applyFilter = function() {
|
||||||
|
@ -26,8 +33,51 @@ function setupExtraNetworksForTab(tabname) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var applySort = function() {
|
||||||
|
var reverse = sortOrder.classList.contains("sortReverse");
|
||||||
|
var sortKey = sort.querySelector("input").value.toLowerCase().replace("sort", "").replaceAll(" ", "_").replace(/_+$/, "").trim();
|
||||||
|
sortKey = sortKey ? "sort" + sortKey.charAt(0).toUpperCase() + sortKey.slice(1) : "";
|
||||||
|
var sortKeyStore = sortKey ? sortKey + (reverse ? "Reverse" : "") : "";
|
||||||
|
if (!sortKey || sortKeyStore == sort.dataset.sortkey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.dataset.sortkey = sortKeyStore;
|
||||||
|
|
||||||
|
var cards = gradioApp().querySelectorAll('#' + tabname + '_extra_tabs div.card');
|
||||||
|
cards.forEach(function(card) {
|
||||||
|
card.originalParentElement = card.parentElement;
|
||||||
|
});
|
||||||
|
var sortedCards = Array.from(cards);
|
||||||
|
sortedCards.sort(function(cardA, cardB) {
|
||||||
|
var a = cardA.dataset[sortKey];
|
||||||
|
var b = cardB.dataset[sortKey];
|
||||||
|
if (!isNaN(a) && !isNaN(b)) {
|
||||||
|
return parseInt(a) - parseInt(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (a < b ? -1 : (a > b ? 1 : 0));
|
||||||
|
});
|
||||||
|
if (reverse) {
|
||||||
|
sortedCards.reverse();
|
||||||
|
}
|
||||||
|
cards.forEach(function(card) {
|
||||||
|
card.remove();
|
||||||
|
});
|
||||||
|
sortedCards.forEach(function(card) {
|
||||||
|
card.originalParentElement.appendChild(card);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
search.addEventListener("input", applyFilter);
|
search.addEventListener("input", applyFilter);
|
||||||
applyFilter();
|
applyFilter();
|
||||||
|
["change", "blur", "click"].forEach(function(evt) {
|
||||||
|
sort.querySelector("input").addEventListener(evt, applySort);
|
||||||
|
});
|
||||||
|
sortOrder.addEventListener("click", function() {
|
||||||
|
sortOrder.classList.toggle("sortReverse");
|
||||||
|
applySort();
|
||||||
|
});
|
||||||
|
|
||||||
extraNetworksApplyFilter[tabname] = applyFilter;
|
extraNetworksApplyFilter[tabname] = applyFilter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ extra_networks_symbol = '\U0001F3B4' # 🎴
|
||||||
switch_values_symbol = '\U000021C5' # ⇅
|
switch_values_symbol = '\U000021C5' # ⇅
|
||||||
restore_progress_symbol = '\U0001F300' # 🌀
|
restore_progress_symbol = '\U0001F300' # 🌀
|
||||||
detect_image_size_symbol = '\U0001F4D0' # 📐
|
detect_image_size_symbol = '\U0001F4D0' # 📐
|
||||||
|
up_down_symbol = '\u2195\ufe0f' # ↕️
|
||||||
|
|
||||||
|
|
||||||
def plaintext_to_html(text):
|
def plaintext_to_html(text):
|
||||||
|
|
|
@ -4,6 +4,7 @@ from pathlib import Path
|
||||||
|
|
||||||
from modules import shared
|
from modules import shared
|
||||||
from modules.images import read_info_from_image, save_image_with_geninfo
|
from modules.images import read_info_from_image, save_image_with_geninfo
|
||||||
|
from modules.ui import up_down_symbol
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
import json
|
import json
|
||||||
import html
|
import html
|
||||||
|
@ -185,6 +186,8 @@ class ExtraNetworksPage:
|
||||||
if search_only and shared.opts.extra_networks_hidden_models == "Never":
|
if search_only and shared.opts.extra_networks_hidden_models == "Never":
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
sort_keys = " ".join([html.escape(f'data-sort-{k}={v}') for k, v in item.get("sort_keys", {}).items()]).strip()
|
||||||
|
|
||||||
args = {
|
args = {
|
||||||
"background_image": background_image,
|
"background_image": background_image,
|
||||||
"style": f"'display: none; {height}{width}'",
|
"style": f"'display: none; {height}{width}'",
|
||||||
|
@ -198,10 +201,23 @@ class ExtraNetworksPage:
|
||||||
"search_term": item.get("search_term", ""),
|
"search_term": item.get("search_term", ""),
|
||||||
"metadata_button": metadata_button,
|
"metadata_button": metadata_button,
|
||||||
"search_only": " search_only" if search_only else "",
|
"search_only": " search_only" if search_only else "",
|
||||||
|
"sort_keys": sort_keys,
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.card_page.format(**args)
|
return self.card_page.format(**args)
|
||||||
|
|
||||||
|
def get_sort_keys(self, path):
|
||||||
|
"""
|
||||||
|
List of default keys used for sorting in the UI.
|
||||||
|
"""
|
||||||
|
pth = Path(path)
|
||||||
|
stat = pth.stat()
|
||||||
|
return {
|
||||||
|
"date_created": int(stat.st_ctime or 0),
|
||||||
|
"date_modified": int(stat.st_mtime or 0),
|
||||||
|
"name": pth.name.lower(),
|
||||||
|
}
|
||||||
|
|
||||||
def find_preview(self, path):
|
def find_preview(self, path):
|
||||||
"""
|
"""
|
||||||
Find a preview PNG for a given path (without extension) and call link_preview on it.
|
Find a preview PNG for a given path (without extension) and call link_preview on it.
|
||||||
|
@ -296,6 +312,8 @@ def create_ui(container, button, tabname):
|
||||||
page_elem.change(fn=lambda: None, _js='function(){applyExtraNetworkFilter(' + json.dumps(tabname) + '); return []}', inputs=[], outputs=[])
|
page_elem.change(fn=lambda: None, _js='function(){applyExtraNetworkFilter(' + json.dumps(tabname) + '); return []}', inputs=[], outputs=[])
|
||||||
|
|
||||||
gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", placeholder="Search...", visible=False)
|
gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", placeholder="Search...", visible=False)
|
||||||
|
gr.Dropdown(choices=['Default Sort', 'Date Created', 'Date Modified', 'Name'], value='Default Sort', elem_id=tabname+"_extra_sort", multiselect=False, visible=False, show_label=False, interactive=True)
|
||||||
|
gr.Button(up_down_symbol, elem_id=tabname+"_extra_sortorder")
|
||||||
button_refresh = gr.Button('Refresh', elem_id=tabname+"_extra_refresh")
|
button_refresh = gr.Button('Refresh', elem_id=tabname+"_extra_refresh")
|
||||||
|
|
||||||
ui.button_save_preview = gr.Button('Save preview', elem_id=tabname+"_save_preview", visible=False)
|
ui.button_save_preview = gr.Button('Save preview', elem_id=tabname+"_save_preview", visible=False)
|
||||||
|
|
|
@ -14,7 +14,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
|
||||||
|
|
||||||
def list_items(self):
|
def list_items(self):
|
||||||
checkpoint: sd_models.CheckpointInfo
|
checkpoint: sd_models.CheckpointInfo
|
||||||
for name, checkpoint in sd_models.checkpoints_list.items():
|
for index, (name, checkpoint) in enumerate(sd_models.checkpoints_list.items()):
|
||||||
path, ext = os.path.splitext(checkpoint.filename)
|
path, ext = os.path.splitext(checkpoint.filename)
|
||||||
yield {
|
yield {
|
||||||
"name": checkpoint.name_for_extra,
|
"name": checkpoint.name_for_extra,
|
||||||
|
@ -24,6 +24,8 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
|
||||||
"search_term": self.search_terms_from_path(checkpoint.filename) + " " + (checkpoint.sha256 or ""),
|
"search_term": self.search_terms_from_path(checkpoint.filename) + " " + (checkpoint.sha256 or ""),
|
||||||
"onclick": '"' + html.escape(f"""return selectCheckpoint({json.dumps(name)})""") + '"',
|
"onclick": '"' + html.escape(f"""return selectCheckpoint({json.dumps(name)})""") + '"',
|
||||||
"local_preview": f"{path}.{shared.opts.samples_format}",
|
"local_preview": f"{path}.{shared.opts.samples_format}",
|
||||||
|
"sort_keys": {'default': index, **self.get_sort_keys(checkpoint.filename)},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def allowed_directories_for_previews(self):
|
def allowed_directories_for_previews(self):
|
||||||
|
|
|
@ -12,7 +12,7 @@ class ExtraNetworksPageHypernetworks(ui_extra_networks.ExtraNetworksPage):
|
||||||
shared.reload_hypernetworks()
|
shared.reload_hypernetworks()
|
||||||
|
|
||||||
def list_items(self):
|
def list_items(self):
|
||||||
for name, path in shared.hypernetworks.items():
|
for index, (name, path) in enumerate(shared.hypernetworks.items()):
|
||||||
path, ext = os.path.splitext(path)
|
path, ext = os.path.splitext(path)
|
||||||
|
|
||||||
yield {
|
yield {
|
||||||
|
@ -23,6 +23,8 @@ class ExtraNetworksPageHypernetworks(ui_extra_networks.ExtraNetworksPage):
|
||||||
"search_term": self.search_terms_from_path(path),
|
"search_term": self.search_terms_from_path(path),
|
||||||
"prompt": json.dumps(f"<hypernet:{name}:") + " + opts.extra_networks_default_multiplier + " + json.dumps(">"),
|
"prompt": json.dumps(f"<hypernet:{name}:") + " + opts.extra_networks_default_multiplier + " + json.dumps(">"),
|
||||||
"local_preview": f"{path}.preview.{shared.opts.samples_format}",
|
"local_preview": f"{path}.preview.{shared.opts.samples_format}",
|
||||||
|
"sort_keys": {'default': index, **self.get_sort_keys(path + ext)},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def allowed_directories_for_previews(self):
|
def allowed_directories_for_previews(self):
|
||||||
|
|
|
@ -13,7 +13,7 @@ class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage):
|
||||||
sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings(force_reload=True)
|
sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings(force_reload=True)
|
||||||
|
|
||||||
def list_items(self):
|
def list_items(self):
|
||||||
for embedding in sd_hijack.model_hijack.embedding_db.word_embeddings.values():
|
for index, embedding in enumerate(sd_hijack.model_hijack.embedding_db.word_embeddings.values()):
|
||||||
path, ext = os.path.splitext(embedding.filename)
|
path, ext = os.path.splitext(embedding.filename)
|
||||||
yield {
|
yield {
|
||||||
"name": embedding.name,
|
"name": embedding.name,
|
||||||
|
@ -23,6 +23,8 @@ class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage):
|
||||||
"search_term": self.search_terms_from_path(embedding.filename),
|
"search_term": self.search_terms_from_path(embedding.filename),
|
||||||
"prompt": json.dumps(embedding.name),
|
"prompt": json.dumps(embedding.name),
|
||||||
"local_preview": f"{path}.preview.{shared.opts.samples_format}",
|
"local_preview": f"{path}.preview.{shared.opts.samples_format}",
|
||||||
|
"sort_keys": {'default': index, **self.get_sort_keys(embedding.filename)},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def allowed_directories_for_previews(self):
|
def allowed_directories_for_previews(self):
|
||||||
|
|
14
style.css
14
style.css
|
@ -734,12 +734,22 @@ footer {
|
||||||
.extra-network-subdirs button{
|
.extra-network-subdirs button{
|
||||||
margin: 0 0.15em;
|
margin: 0 0.15em;
|
||||||
}
|
}
|
||||||
.extra-networks .tab-nav .search{
|
.extra-networks .tab-nav .search,
|
||||||
|
.extra-networks .tab-nav .sort,
|
||||||
|
.extra-networks .tab-nav .sortorder{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-width: 16em;
|
|
||||||
margin: 0.3em;
|
margin: 0.3em;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extra-networks .tab-nav .search {
|
||||||
width: 16em;
|
width: 16em;
|
||||||
|
max-width: 16em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extra-networks .tab-nav .sort {
|
||||||
|
width: 12em;
|
||||||
|
max-width: 12em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#txt2img_extra_view, #img2img_extra_view {
|
#txt2img_extra_view, #img2img_extra_view {
|
||||||
|
|
Loading…
Reference in New Issue