Added Available tab to extensions UI.
This commit is contained in:
parent
5c9b3625fa
commit
5b0f624bdc
|
@ -22,3 +22,14 @@ function extensions_check(){
|
||||||
|
|
||||||
return []
|
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()
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ import html
|
||||||
from modules import extensions, shared, paths
|
from modules import extensions, shared, paths
|
||||||
|
|
||||||
|
|
||||||
|
available_extensions = {"extensions": []}
|
||||||
|
|
||||||
|
|
||||||
def check_access():
|
def check_access():
|
||||||
assert not shared.cmd_opts.disable_extension_access, "extension access disabed because of commandline flags"
|
assert not shared.cmd_opts.disable_extension_access, "extension access disabed because of commandline flags"
|
||||||
|
|
||||||
|
@ -96,6 +99,14 @@ def extension_table():
|
||||||
return code
|
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):
|
def install_extension_from_url(dirname, url):
|
||||||
check_access()
|
check_access()
|
||||||
|
|
||||||
|
@ -103,14 +114,15 @@ def install_extension_from_url(dirname, url):
|
||||||
|
|
||||||
if dirname is None or dirname == "":
|
if dirname is None or dirname == "":
|
||||||
*parts, last_part = url.split('/')
|
*parts, last_part = url.split('/')
|
||||||
last_part = last_part.replace(".git", "")
|
last_part = normalize_git_url(last_part)
|
||||||
|
|
||||||
dirname = last_part
|
dirname = last_part
|
||||||
|
|
||||||
target_dir = os.path.join(extensions.extensions_dir, dirname)
|
target_dir = os.path.join(extensions.extensions_dir, dirname)
|
||||||
assert not os.path.exists(target_dir), f'Extension directory already exists: {target_dir}'
|
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)
|
tmpdir = os.path.join(paths.script_path, "tmp", dirname)
|
||||||
|
|
||||||
|
@ -128,18 +140,80 @@ def install_extension_from_url(dirname, url):
|
||||||
shutil.rmtree(tmpdir, True)
|
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():
|
def create_ui():
|
||||||
import modules.ui
|
import modules.ui
|
||||||
|
|
||||||
with gr.Blocks(analytics_enabled=False) as ui:
|
with gr.Blocks(analytics_enabled=False) as ui:
|
||||||
with gr.Tabs(elem_id="tabs_extensions") as tabs:
|
with gr.Tabs(elem_id="tabs_extensions") as tabs:
|
||||||
with gr.TabItem("Installed"):
|
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():
|
with gr.Row():
|
||||||
apply = gr.Button(value="Apply and restart UI", variant="primary")
|
apply = gr.Button(value="Apply and restart UI", variant="primary")
|
||||||
check = gr.Button(value="Check for updates")
|
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())
|
extensions_table = gr.HTML(lambda: extension_table())
|
||||||
|
|
||||||
|
@ -157,16 +231,38 @@ def create_ui():
|
||||||
outputs=[extensions_table],
|
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"):
|
with gr.TabItem("Install from URL"):
|
||||||
install_url = gr.Text(label="URL for extension's git repository")
|
install_url = gr.Text(label="URL for extension's git repository")
|
||||||
install_dirname = gr.Text(label="Local directory name", placeholder="Leave empty for auto")
|
install_dirname = gr.Text(label="Local directory name", placeholder="Leave empty for auto")
|
||||||
intall_button = gr.Button(value="Install", variant="primary")
|
install_button = gr.Button(value="Install", variant="primary")
|
||||||
intall_result = gr.HTML(elem_id="extension_install_result")
|
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()]),
|
fn=modules.ui.wrap_gradio_call(install_extension_from_url, extra_outputs=[gr.update()]),
|
||||||
inputs=[install_dirname, install_url],
|
inputs=[install_dirname, install_url],
|
||||||
outputs=[extensions_table, intall_result],
|
outputs=[extensions_table, install_result],
|
||||||
)
|
)
|
||||||
|
|
||||||
return ui
|
return ui
|
||||||
|
|
|
@ -532,16 +532,16 @@ img2maskimg, #img2maskimg > .h-60, #img2maskimg > .h-60 > div, #img2maskimg > .h
|
||||||
|
|
||||||
/* Extensions */
|
/* Extensions */
|
||||||
|
|
||||||
#extensions{
|
#tab_extensions table{
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
#extensions td, #extensions th{
|
#tab_extensions table td, #tab_extensions table th{
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
padding: 0.25em 0.5em;
|
padding: 0.25em 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#extensions input[type="checkbox"]{
|
#tab_extensions table input[type="checkbox"]{
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,6 +549,9 @@ img2maskimg, #img2maskimg > .h-60, #img2maskimg > .h-60 > div, #img2maskimg > .h
|
||||||
max-width: 16em;
|
max-width: 16em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tab_extensions input[disabled="disabled"]{
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
/* The following handles localization for right-to-left (RTL) languages like Arabic.
|
/* 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.
|
The rtl media type will only be activated by the logic in javascript/localization.js.
|
||||||
|
|
Loading…
Reference in New Issue