diff --git a/.eslintrc.json b/.eslintrc.json index 520fad0b9..10d4062ed 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -54,6 +54,7 @@ "getUICurrentTabContent": "readonly", //ui.js "opts": "writable", + "sortUIElements": "readonly", "all_gallery_buttons": "readonly", "selected_gallery_button": "readonly", "selected_gallery_index": "readonly", diff --git a/CHANGELOG.md b/CHANGELOG.md index cb04ff4fc..4f23a41c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,29 +1,37 @@ # Change Log for SD.Next -## Update for 2023-08-29 +## Update for 2023-08-30 -- general: - - all system and image paths are now relative by default - - add settings validation when performing load/save - - settings tab in ui now shows settings that are changed from default values - - settings tab switch to compact view - - enable batch **img2img** scale-by workflows - now you can batch process with rescaling based on eah individual original image size +- general: + - redesigned **settings** + - new layout with separated sections: + *settings, ui config, licenses, system info, benchmark, models* + - **system info** tab is now part of settings + when running outside of sdnext, system info is shown in main ui + - all system and image paths are now relative by default + - add settings validation when performing load/save + - settings tab in ui now shows settings that are changed from default values + - settings tab switch to compact view - update **gradio** major version this may result in some smaller layout changes since its a major version change however, browser page load is now much faster - - optimize model hashing - - add cli param `--skip-all` that skips all installer checks - use at personal discretion, but it can be useful for bulk deployments + - optimizations: + - optimize model hashing + - add cli param `--skip-all` that skips all installer checks + use at personal discretion, but it can be useful for bulk deployments + - add model **precompile** option (when model compile is enbled) + - **extra network** folder info caching + results in much faster startup when you have large number of extra networks + - fixes: + - fix extra networks previews + - fix gradio gallery + - css fixes + - improved extensions compatibility (e.g. sd-cn-animation) - add **openvino** (experimental) cpu optimized model compile and inference enable with `--use-openvino` thanks @disty0 - - add model **precompile** option (when model compile is enbled) - - **extra network** folder info caching - results in much faster startup when you have large number of extra networks - - fix extra networks previews - - fix gradio gallery - - css fixes + - enable batch **img2img** scale-by workflows + now you can batch process with rescaling based on eah individual original image size ## Update for 2023-08-20 diff --git a/extensions-builtin/sd-extension-system-info b/extensions-builtin/sd-extension-system-info index 19d190e71..761cf83c9 160000 --- a/extensions-builtin/sd-extension-system-info +++ b/extensions-builtin/sd-extension-system-info @@ -1 +1 @@ -Subproject commit 19d190e71b2f1399623519db741d2a6bf8d2c86c +Subproject commit 761cf83c93d8ac64b212ccd4a93b8efc2eaae305 diff --git a/javascript/setHints.js b/javascript/setHints.js index d8439ace3..d65907657 100644 --- a/javascript/setHints.js +++ b/javascript/setHints.js @@ -85,6 +85,7 @@ async function setHints() { } const t1 = performance.now(); log('setHints', { type: localeData.type, elements: elements.length, localized, hints, data: localeData.data.length, time: t1 - t0 }); + sortUIElements(); removeSplash(); // validateHints(elements, localeData.data) } diff --git a/javascript/style.css b/javascript/style.css index 20f4c5bd6..1fd04582a 100644 --- a/javascript/style.css +++ b/javascript/style.css @@ -113,6 +113,7 @@ div#extras_scale_to_tab div.form{ flex-direction: row; } .tooltip-show { opacity: 0.9; } /* settings */ +#si-sparkline-memo, #si-sparkline-load { background-color: #111; } .licenses { display: block !important; } #quicksettings { width: fit-content; align-items: end; } #quicksettings > div, #quicksettings > fieldset{ max-width: 20em; min-width: 24em; padding: 0; border: none; box-shadow: none; background: none; } diff --git a/javascript/ui.js b/javascript/ui.js index c455765ba..001d4df30 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -277,7 +277,7 @@ onAfterUiUpdate(async () => { promptsInitialized = true; } - sortUIElements(); + // sortUIElements(); registerTextarea('txt2img_prompt', 'txt2img_token_counter', 'txt2img_token_button'); registerTextarea('txt2img_neg_prompt', 'txt2img_negative_token_counter', 'txt2img_negative_token_button'); registerTextarea('img2img_prompt', 'img2img_token_counter', 'img2img_token_button'); diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py index a5513ad3f..29cd9470a 100644 --- a/modules/script_callbacks.py +++ b/modules/script_callbacks.py @@ -443,5 +443,4 @@ def on_script_unloaded(callback): def on_before_ui(callback): """register a function to be called before the UI is created.""" - add_callback(callback_map['callbacks_before_ui'], callback) diff --git a/modules/ui.py b/modules/ui.py index b2880d4a5..949cdf275 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -33,6 +33,8 @@ modules.errors.install() mimetypes.init() mimetypes.add_type('application/javascript', '.js') log = modules.shared.log +ui_system_tabs = None + if not cmd_opts.share and not cmd_opts.listen: # fix gradio phoning home @@ -328,6 +330,10 @@ def get_value_for_setting(key): return gr.update(value=value, **args) +def ordered_ui_categories(): + return [] # dummy + + def create_override_settings_dropdown(tabname, row): # pylint: disable=unused-argument dropdown = gr.Dropdown([], label="Override settings", visible=False, elem_id=f"{tabname}_override_settings", multiselect=True) dropdown.change(fn=lambda x: gr.Dropdown.update(visible=len(x) > 0), inputs=[dropdown], outputs=[dropdown]) @@ -993,66 +999,75 @@ def create_ui(startup_timer = None): with gr.Blocks(analytics_enabled=False) as settings_interface: with gr.Row(): - settings_submit = gr.Button(value="Apply settings", variant='primary', elem_id="settings_submit") restart_submit = gr.Button(value="Restart server", variant='primary', elem_id="restart_submit") shutdown_submit = gr.Button(value="Shutdown server", variant='primary', elem_id="shutdown_submit") - preview_theme = gr.Button(value="Preview theme", variant='primary', elem_id="settings_preview_theme") - defaults_submit = gr.Button(value="Restore defaults", variant='primary', elem_id="defaults_submit") unload_sd_model = gr.Button(value='Unload checkpoint', variant='primary', elem_id="sett_unload_sd_model") reload_sd_model = gr.Button(value='Reload checkpoint', variant='primary', elem_id="sett_reload_sd_model") - # reload_script_bodies = gr.Button(value='Reload scripts', variant='primary', elem_id="settings_reload_script_bodies") - with gr.Row(): - _settings_search = gr.Text(label="Search", elem_id="settings_search") - result = gr.HTML(elem_id="settings_result") - quicksettings_names = opts.quicksettings_list - quicksettings_names = {x: i for i, x in enumerate(quicksettings_names) if x != 'quicksettings'} - quicksettings_list = [] + with gr.Tabs(elem_id="system") as system_tabs: + global ui_system_tabs # pylint: disable=global-statement + ui_system_tabs = system_tabs + with gr.TabItem("Settings", id="system_settings", elem_id="system_settings_tab"): - previous_section = [] - tab_item_keys = [] - current_tab = None - current_row = None - with gr.Tabs(elem_id="settings"): - for i, (k, item) in enumerate(opts.data_labels.items()): - section_must_be_skipped = item.section[0] is None - if previous_section != item.section and not section_must_be_skipped: - elem_id, text = item.section + with gr.Row(): + settings_submit = gr.Button(value="Apply settings", variant='primary', elem_id="settings_submit") + preview_theme = gr.Button(value="Preview theme", variant='primary', elem_id="settings_preview_theme") + defaults_submit = gr.Button(value="Restore defaults", variant='primary', elem_id="defaults_submit") + + with gr.Row(): + _settings_search = gr.Text(label="Search", elem_id="settings_search") + + result = gr.HTML(elem_id="settings_result") + quicksettings_names = opts.quicksettings_list + quicksettings_names = {x: i for i, x in enumerate(quicksettings_names) if x != 'quicksettings'} + quicksettings_list = [] + + previous_section = [] + tab_item_keys = [] + current_tab = None + current_row = None + with gr.Tabs(elem_id="settings"): + for i, (k, item) in enumerate(opts.data_labels.items()): + section_must_be_skipped = item.section[0] is None + if previous_section != item.section and not section_must_be_skipped: + elem_id, text = item.section + if current_tab is not None and len(previous_section) > 0: + create_dirty_indicator(previous_section[0], tab_item_keys) + tab_item_keys = [] + current_row.__exit__() + current_tab.__exit__() + current_tab = gr.TabItem(elem_id=f"settings_{elem_id}", label=text) + current_tab.__enter__() + current_row = gr.Column(variant='compact') + current_row.__enter__() + previous_section = item.section + if k in quicksettings_names and not modules.shared.cmd_opts.freeze: + quicksettings_list.append((i, k, item)) + components.append(dummy_component) + elif section_must_be_skipped: + components.append(dummy_component) + else: + component = create_setting_component(k) + component_dict[k] = component + tab_item_keys.append(k) + components.append(component) if current_tab is not None and len(previous_section) > 0: create_dirty_indicator(previous_section[0], tab_item_keys) tab_item_keys = [] current_row.__exit__() current_tab.__exit__() - current_tab = gr.TabItem(elem_id=f"settings_{elem_id}", label=text) - current_tab.__enter__() - current_row = gr.Column(variant='compact') - current_row.__enter__() - previous_section = item.section - if k in quicksettings_names and not modules.shared.cmd_opts.freeze: - quicksettings_list.append((i, k, item)) - components.append(dummy_component) - elif section_must_be_skipped: - components.append(dummy_component) - else: - component = create_setting_component(k) - component_dict[k] = component - tab_item_keys.append(k) - components.append(component) - if current_tab is not None and len(previous_section) > 0: - create_dirty_indicator(previous_section[0], tab_item_keys) - tab_item_keys = [] - current_row.__exit__() - current_tab.__exit__() - request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications", visible=False) - with gr.TabItem("User interface defaults", id="defaults", elem_id="settings_tab_defaults"): + request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications", visible=False) + with gr.TabItem("Show all pages", variant='primary', elem_id="settings_show_all_pages"): + create_dirty_indicator("show_all_pages", [], interactive=False) + + with gr.TabItem("UI Config", id="system_config", elem_id="system_config_tab"): loadsave.create_ui() create_dirty_indicator("tab_defaults", [], interactive=False) - with gr.TabItem("Licenses", id="licenses", elem_id="settings_tab_licenses"): + + with gr.TabItem("Licenses", id="system_licenses", elem_id="system_tab_licenses"): gr.HTML(modules.shared.html("licenses.html"), elem_id="licenses", elem_classes="licenses") create_dirty_indicator("tab_licenses", [], interactive=False) - with gr.TabItem("Show all pages", variant='primary', elem_id="settings_show_all_pages"): - create_dirty_indicator("show_all_pages", [], interactive=False) def unload_sd_weights(): modules.sd_models.unload_model_weights(op='model') @@ -1076,7 +1091,7 @@ def create_ui(startup_timer = None): (models_interface, "Models", "models"), ] interfaces += script_callbacks.ui_tabs_callback() - interfaces += [(settings_interface, "Settings", "settings")] + interfaces += [(settings_interface, "System", "system")] extensions_interface = ui_extensions.create_ui() interfaces += [(extensions_interface, "Extensions", "extensions")] startup_timer.record("ui-extensions") @@ -1095,12 +1110,16 @@ def create_ui(startup_timer = None): with gr.Tabs(elem_id="tabs") as tabs: for interface, label, ifid in interfaces: - if label in modules.shared.opts.hidden_tabs: + if interface is None: + continue + if label in modules.shared.opts.hidden_tabs or label == '': continue with gr.TabItem(label, id=ifid, elem_id=f"tab_{ifid}"): interface.render() for interface, _label, ifid in interfaces: - if ifid in ["extensions", "settings"]: + if interface is None: + continue + if ifid in ["extensions", "system"]: continue loadsave.add_block(interface, ifid) loadsave.add_component(f"webui/Tabs@{tabs.elem_id}", tabs) diff --git a/modules/ui_common.py b/modules/ui_common.py index 6ef5e8800..1b0484cc0 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -165,7 +165,7 @@ def create_output_panel(tabname, outdir): with gr.Column(variant='panel', elem_id=f"{tabname}_results"): with gr.Group(elem_id=f"{tabname}_gallery_container"): # columns are for <576px, <768px, <992px, <1200px, <1400px, >1400px - result_gallery = gr.Gallery(value=[], label='Output', show_label=False, show_download_button=True, elem_id=f"{tabname}_gallery", container=False, preview=True, columns=[1,2,3,4,5,6], object_fit='scale-down') + result_gallery = gr.Gallery(value=[], label='Output', show_label=False, show_download_button=True, elem_id=f"{tabname}_gallery", container=False, preview=True, columns=[1,2,3,4,5,6], object_fit='scale-down') with gr.Column(elem_id=f"{tabname}_footer", elem_classes="gallery_footer"): with gr.Row(elem_id=f"image_buttons_{tabname}", elem_classes="image-buttons"):