From 24da36282e62f7d1f57848a078922a1450cc3e86 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Tue, 30 Dec 2025 00:10:13 -0800 Subject: [PATCH] Update extension table layout - Use icons on Modern UI to better fit being in a narrow sidebar. (Full labels kept for Standard UI) - Swap Status and Enabled columns. - Improve status and enabled element spacing on Standard UI. - Minor readability improvements to extension information. - *Internal*: Add `if_modern()` function to `shared.py` to switch between two inputs depending on whether the Modern UI is being used or not. --- modules/shared.py | 15 ++++++++++++++- modules/ui_extensions.py | 38 +++++++++++++++++++++----------------- modules/ui_symbols.py | 2 ++ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index 9d6bc157b..568679d1b 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -5,7 +5,7 @@ import sys import time import contextlib from enum import Enum -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeVar import gradio as gr from modules.json_helpers import readfile, writefile # pylint: disable=W0611 from modules.shared_helpers import listdir, walk_files, html_path, html, req, total_tqdm # pylint: disable=W0611 @@ -30,6 +30,9 @@ if TYPE_CHECKING: from modules.shared_legacy import LegacyOption from modules.ui_extra_networks import ExtraNetworksPage +M = TypeVar("M") +S = TypeVar("S") + class Backend(Enum): ORIGINAL = 1 @@ -117,6 +120,16 @@ list_checkpoint_tiles = list_checkpoint_titles # alias for legacy typo default_checkpoint = list_checkpoint_titles()[0] if len(list_checkpoint_titles()) > 0 else "model.safetensors" +def if_modern(modern: M, standard: S = None) -> M | S: + """Return input depending on whether Modern UI is being used or not. + + Args: + modern (Any): Value to return if Modern UI is being used. + standard (Any, optional): Value to return if Modern UI is NOT being used. Defaults to None. + """ + return modern if opts.theme_type == "Modern" else standard + + def is_url(string): from urllib.parse import urlparse parsed_url = urlparse(string) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 0f427ba8c..15821781c 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -32,6 +32,10 @@ sort_ordering = { re_snake_case = re.compile(r'_(?=[a-zA-z0-9])') re_camelCase = re.compile(r'(?<=[a-z])([A-Z])') +th_status = shared.if_modern(f'{ui_symbols.info_btn}', "Status") +th_enabled = shared.if_modern(f'{ui_symbols.check_btn}', "Enabled") + + def get_installed(ext): installed = [e for e in extensions.extensions if (e.remote or '').startswith(ext['url'].replace('.git', ''))] return installed[0] if len(installed) > 0 else None @@ -279,7 +283,7 @@ def make_wrappable_html(text: str) -> str: def create_html(search_text, sort_column): # shared.log.debug(f'Extensions manager: refresh list search="{search_text}" sort="{sort_column}"') - code = """ + code = f"""
@@ -293,8 +297,8 @@ def create_html(search_text, sort_column): - - + + @@ -377,7 +381,7 @@ def create_html(search_text, sort_column): stats['enabled'] += 1 type_code = f"""
{"SYSTEM" if ext['is_builtin'] else 'USER'}
""" version_code = f"""
{ext['version']}
""" - enabled_code = f"""""" + enabled_code = f"""""" masked_path = html.escape(ext.get("path", "").replace('\\', '/')) if not ext['is_builtin']: install_code = f"""""" @@ -389,36 +393,36 @@ def create_html(search_text, sort_column): if ext.get('status', None) is None or type(ext['status']) == str: # old format ext['status'] = 0 if ext['url'] is None or ext['url'] == '': - status = f"
{ui_symbols.svg_bullet.style('#00C0FD')}
" + status = f"
{ui_symbols.svg_bullet.style('#00C0FD')}
" elif ext['status'] > 0: if ext['status'] == 1: - status = f"
{ui_symbols.svg_bullet.style('#00FD9C')}
" + status = f"
{ui_symbols.svg_bullet.style('#00FD9C')}
" elif ext['status'] == 2: - status = f"
{ui_symbols.svg_bullet.style('#FFC300')}
" + status = f"
{ui_symbols.svg_bullet.style('#FFC300')}
" elif ext['status'] == 3: - status = f"
{ui_symbols.svg_bullet.style('#FFC300')}
" + status = f"
{ui_symbols.svg_bullet.style('#FFC300')}
" elif ext['status'] == 4: - status = f"
{ui_symbols.svg_bullet.style('#4E22FF')}
" + status = f"
{ui_symbols.svg_bullet.style('#4E22FF')}
" elif ext['status'] == 5: - status = f"
{ui_symbols.svg_bullet.style('#CE0000')}
" + status = f"
{ui_symbols.svg_bullet.style('#CE0000')}
" elif ext['status'] == 6: - status = f"
{ui_symbols.svg_bullet.style('#AEAEAE')}
" + status = f"
{ui_symbols.svg_bullet.style('#AEAEAE')}
" else: - status = f"
{ui_symbols.svg_bullet.style('#008EBC')}
" + status = f"
{ui_symbols.svg_bullet.style('#008EBC')}
" else: if updated < datetime.now(timezone.utc) - timedelta(6*30): # TZ-aware - status = f"
{ui_symbols.svg_bullet.style('#C000CF')}
" + status = f"
{ui_symbols.svg_bullet.style('#C000CF')}
" else: - status = f"
{ui_symbols.svg_bullet.style('#7C7C7C')}
" + status = f"
{ui_symbols.svg_bullet.style('#7C7C7C')}
" code += f""" - {enabled_code} + diff --git a/modules/ui_symbols.py b/modules/ui_symbols.py index d2749819d..ba10b2b5f 100644 --- a/modules/ui_symbols.py +++ b/modules/ui_symbols.py @@ -33,6 +33,8 @@ search = '🔍' preview = 'đŸ–ŧī¸' image = 'đŸ–Œī¸' resize = '⁜' +check_btn = 'â˜‘ī¸' +info_btn = 'â„šī¸' # noqa: RUF001 interrogate = '\uf46b' # Telescope icon in Noto Sans. Previously 'â™ģ' bullet = '⃝' vision = '\uf06e' # Font Awesome eye icon (more minimalistic)
StatusEnabled{th_enabled}{th_status} Extension Description Type
{status} {status} {make_wrappable_html(ext.get("name", "unknown"))}
{tags_text}
{html.escape(ext.get("description", ""))} -

Created {html.escape(dt('created'))} | Added {html.escape(dt('added'))} | Pushed {html.escape(dt('pushed'))} | Updated {html.escape(dt('updated'))}

-

{author} | Stars {html.escape(str(ext.get('stars', 0)))} | Size {html.escape(str(ext.get('size', 0)))} | Commits {html.escape(str(ext.get('commits', 0)))} | Issues {html.escape(str(ext.get('issues', 0)))} | Trending {html.escape(str(ext['sort_trending']))}

+

Created: {html.escape(dt('created'))} | Added: {html.escape(dt('added'))} | Pushed: {html.escape(dt('pushed'))} | Updated: {html.escape(dt('updated'))}

+

{author} | Stars: {html.escape(str(ext.get('stars', 0)))} | Size: {html.escape(str(ext.get('size', 0)))} | Commits: {html.escape(str(ext.get('commits', 0)))} | Issues: {html.escape(str(ext.get('issues', 0)))} | Trending: {html.escape(str(ext['sort_trending']))}

{type_code} {version_code}