Sfoglia il codice sorgente

Added Available tab to extensions UI.

AUTOMATIC 2 anni fa
parent
commit
5b0f624bdc
3 ha cambiato i file con 122 aggiunte e 12 eliminazioni
  1. 12 1
      javascript/extensions.js
  2. 104 8
      modules/ui_extensions.py
  3. 6 3
      style.css

+ 12 - 1
javascript/extensions.js

@@ -21,4 +21,15 @@ function extensions_check(){
     })
 
     return []
-}
+}
+
+function install_extension_from_index(button, url){
+    button.disabled = "disabled"
+    button.value = "Installing..."
+
+    textarea = gradioApp().querySelector('#extension_to_install textarea')
+    textarea.value = url
+	textarea.dispatchEvent(new Event("input", { bubbles: true }))
+
+    gradioApp().querySelector('#install_extension_button').click()
+}

+ 104 - 8
modules/ui_extensions.py

@@ -13,6 +13,9 @@ import html
 from modules import extensions, shared, paths
 
 
+available_extensions = {"extensions": []}
+
+
 def check_access():
     assert not shared.cmd_opts.disable_extension_access, "extension access disabed because of commandline flags"
 
@@ -96,6 +99,14 @@ def extension_table():
     return code
 
 
+def normalize_git_url(url):
+    if url is None:
+        return ""
+
+    url = url.replace(".git", "")
+    return url
+
+
 def install_extension_from_url(dirname, url):
     check_access()
 
@@ -103,14 +114,15 @@ def install_extension_from_url(dirname, url):
 
     if dirname is None or dirname == "":
         *parts, last_part = url.split('/')
-        last_part = last_part.replace(".git", "")
+        last_part = normalize_git_url(last_part)
 
         dirname = last_part
 
     target_dir = os.path.join(extensions.extensions_dir, dirname)
     assert not os.path.exists(target_dir), f'Extension directory already exists: {target_dir}'
 
-    assert len([x for x in extensions.extensions if x.remote == url]) == 0, 'Extension with this URL is already installed'
+    normalized_url = normalize_git_url(url)
+    assert len([x for x in extensions.extensions if normalize_git_url(x.remote) == normalized_url]) == 0, 'Extension with this URL is already installed'
 
     tmpdir = os.path.join(paths.script_path, "tmp", dirname)
 
@@ -128,18 +140,80 @@ def install_extension_from_url(dirname, url):
         shutil.rmtree(tmpdir, True)
 
 
+def install_extension_from_index(url):
+    ext_table, message = install_extension_from_url(None, url)
+
+    return refresh_available_extensions_from_data(), ext_table, message
+
+
+def refresh_available_extensions(url):
+    global available_extensions
+
+    import urllib.request
+    with urllib.request.urlopen(url) as response:
+        text = response.read()
+
+    available_extensions = json.loads(text)
+
+    return url, refresh_available_extensions_from_data(), ''
+
+
+def refresh_available_extensions_from_data():
+    extlist = available_extensions["extensions"]
+    installed_extension_urls = {normalize_git_url(extension.remote): extension.name for extension in extensions.extensions}
+
+    code = f"""<!-- {time.time()} -->
+    <table id="available_extensions">
+        <thead>
+            <tr>
+                <th>Extension</th>
+                <th>Description</th>
+                <th>Action</th>
+            </tr>
+        </thead>
+        <tbody>
+    """
+
+    for ext in extlist:
+        name = ext.get("name", "noname")
+        url = ext.get("url", None)
+        description = ext.get("description", "")
+
+        if url is None:
+            continue
+
+        existing = installed_extension_urls.get(normalize_git_url(url), None)
+
+        install_code = f"""<input onclick="install_extension_from_index(this, '{html.escape(url)}')" type="button" value="{"Install" if not existing else "Installed"}" {"disabled=disabled" if existing else ""} class="gr-button gr-button-lg gr-button-secondary">"""
+
+        code += f"""
+            <tr>
+                <td><a href="{html.escape(url)}">{html.escape(name)}</a></td>
+                <td>{html.escape(description)}</td>
+                <td>{install_code}</td>
+            </tr>
+    """
+
+    code += """
+        </tbody>
+    </table>
+    """
+
+    return code
+
+
 def create_ui():
     import modules.ui
 
     with gr.Blocks(analytics_enabled=False) as ui:
         with gr.Tabs(elem_id="tabs_extensions") as tabs:
             with gr.TabItem("Installed"):
-                extensions_disabled_list = gr.Text(elem_id="extensions_disabled_list", visible=False)
-                extensions_update_list = gr.Text(elem_id="extensions_update_list", visible=False)
 
                 with gr.Row():
                     apply = gr.Button(value="Apply and restart UI", variant="primary")
                     check = gr.Button(value="Check for updates")
+                    extensions_disabled_list = gr.Text(elem_id="extensions_disabled_list", visible=False).style(container=False)
+                    extensions_update_list = gr.Text(elem_id="extensions_update_list", visible=False).style(container=False)
 
                 extensions_table = gr.HTML(lambda: extension_table())
 
@@ -157,16 +231,38 @@ def create_ui():
                     outputs=[extensions_table],
                 )
 
+            with gr.TabItem("Available"):
+                with gr.Row():
+                    refresh_available_extensions_button = gr.Button(value="Load from:", variant="primary")
+                    available_extensions_index = gr.Text(value="https://raw.githubusercontent.com/wiki/AUTOMATIC1111/stable-diffusion-webui/Extensions-index.md", label="Extension index URL").style(container=False)
+                    extension_to_install = gr.Text(elem_id="extension_to_install", visible=False)
+                    install_extension_button = gr.Button(elem_id="install_extension_button", visible=False)
+
+                install_result = gr.HTML()
+                available_extensions_table = gr.HTML()
+
+                refresh_available_extensions_button.click(
+                    fn=modules.ui.wrap_gradio_call(refresh_available_extensions, extra_outputs=[gr.update(), gr.update()]),
+                    inputs=[available_extensions_index],
+                    outputs=[available_extensions_index, available_extensions_table, install_result],
+                )
+
+                install_extension_button.click(
+                    fn=modules.ui.wrap_gradio_call(install_extension_from_index, extra_outputs=[gr.update(), gr.update()]),
+                    inputs=[extension_to_install],
+                    outputs=[available_extensions_table, extensions_table, install_result],
+                )
+
             with gr.TabItem("Install from URL"):
                 install_url = gr.Text(label="URL for extension's git repository")
                 install_dirname = gr.Text(label="Local directory name", placeholder="Leave empty for auto")
-                intall_button = gr.Button(value="Install", variant="primary")
-                intall_result = gr.HTML(elem_id="extension_install_result")
+                install_button = gr.Button(value="Install", variant="primary")
+                install_result = gr.HTML(elem_id="extension_install_result")
 
-                intall_button.click(
+                install_button.click(
                     fn=modules.ui.wrap_gradio_call(install_extension_from_url, extra_outputs=[gr.update()]),
                     inputs=[install_dirname, install_url],
-                    outputs=[extensions_table, intall_result],
+                    outputs=[extensions_table, install_result],
                 )
 
     return ui

+ 6 - 3
style.css

@@ -532,16 +532,16 @@ img2maskimg, #img2maskimg > .h-60, #img2maskimg > .h-60 > div, #img2maskimg > .h
 
 /* Extensions */
 
-#extensions{
+#tab_extensions table{
     border-collapse: collapse;
 }
 
-#extensions td, #extensions th{
+#tab_extensions table td, #tab_extensions table th{
     border: 1px solid #ccc;
     padding: 0.25em 0.5em;
 }
 
-#extensions input[type="checkbox"]{
+#tab_extensions table input[type="checkbox"]{
     margin-right: 0.5em;
 }
 
@@ -549,6 +549,9 @@ img2maskimg, #img2maskimg > .h-60, #img2maskimg > .h-60 > div, #img2maskimg > .h
     max-width: 16em;
 }
 
+#tab_extensions input[disabled="disabled"]{
+    opacity: 0.5;
+}
 
 /* The following handles localization for right-to-left (RTL) languages like Arabic.
 The rtl media type will only be activated by the logic in javascript/localization.js.