0
0
mirror of https://gitflic.ru/project/maks1ms/ocab.git synced 2025-01-11 17:28:12 +03:00
This commit is contained in:
Maxim Slipenko 2024-07-21 20:01:50 +03:00
parent d52864a231
commit 34c365178b
4 changed files with 102 additions and 70 deletions

14
poetry.lock generated
View File

@ -2053,18 +2053,18 @@ files = [
[[package]]
name = "setuptools"
version = "71.0.1"
version = "71.0.4"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "setuptools-71.0.1-py3-none-any.whl", hash = "sha256:1eb8ef012efae7f6acbc53ec0abde4bc6746c43087fd215ee09e1df48998711f"},
{file = "setuptools-71.0.1.tar.gz", hash = "sha256:c51d7fd29843aa18dad362d4b4ecd917022131425438251f4e3d766c964dd1ad"},
{file = "setuptools-71.0.4-py3-none-any.whl", hash = "sha256:ed2feca703be3bdbd94e6bb17365d91c6935c6b2a8d0bb09b66a2c435ba0b1a5"},
{file = "setuptools-71.0.4.tar.gz", hash = "sha256:48297e5d393a62b7cb2a10b8f76c63a73af933bd809c9e0d0d6352a1a0135dd8"},
]
[package.extras]
core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (<7.4)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
@ -2230,13 +2230,13 @@ zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "uvicorn"
version = "0.30.1"
version = "0.30.3"
description = "The lightning-fast ASGI server."
optional = false
python-versions = ">=3.8"
files = [
{file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"},
{file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"},
{file = "uvicorn-0.30.3-py3-none-any.whl", hash = "sha256:94a3608da0e530cea8f69683aa4126364ac18e3826b6630d1a65f4638aade503"},
{file = "uvicorn-0.30.3.tar.gz", hash = "sha256:0d114d0831ff1adbf231d358cbf42f17333413042552a624ea6a9b4c33dcfd81"},
]
[package.dependencies]

View File

@ -1,3 +1,4 @@
import time
from typing import Any, Dict, List, Optional, Union
import yaml
@ -6,7 +7,7 @@ import yaml
try:
import dash_bootstrap_components as dbc
from dash_extensions.enrich import Input, Output, dcc, html
from dash_extensions.enrich import ALL, Input, Output, State, dcc, html
DASH_AVAILABLE = True
except ImportError:
@ -102,9 +103,10 @@ class ConfigManager:
self.set_nested_setting(self._config, key, value)
self.save_config()
def get_settings_layout(self):
def get_settings_layout(self, prefix):
from dash_extensions.enrich import DashBlueprint
self._prefix = prefix
bp = DashBlueprint()
def create_layout():
@ -138,22 +140,28 @@ class ConfigManager:
if not meta.get("is_private"):
row = []
label_text = meta.get("pretty_name", key)
if not label_text:
label_text = key
if meta.get("type") != "checkbox":
row.append(dbc.Label(label_text))
component_id = {
"type": "setting",
"key": "-".join(current_key_list),
"key": "::".join(current_key_list),
}
if meta.get("type") == "string":
component = dbc.Input(
id=component_id, type="text", value=value
id=component_id,
type="text",
value=value,
)
elif meta.get("type") == "number":
component = dbc.Input(
id=component_id, type="number", value=value
id=component_id,
type="number",
value=value,
)
elif meta.get("type") == "checkbox":
component = dbc.Col(
@ -161,11 +169,7 @@ class ConfigManager:
dbc.Checkbox(
id=component_id,
value=value,
label=dbc.Label(
label_text,
style={"margin-right": "10px"},
check=True,
),
label=label_text,
)
]
)
@ -175,7 +179,9 @@ class ConfigManager:
for opt in meta.get("options", [])
]
component = dcc.Dropdown(
id=component_id, options=options, value=value
id=component_id,
options=options,
value=value,
)
else:
continue
@ -195,17 +201,15 @@ class ConfigManager:
[
html.H1("Настройки"),
dbc.Form(settings_components),
html.Div(id="save-confirmation"),
dbc.Button(
"Сохранить",
id="save-settings",
color="primary",
className="mt-3",
className="mt-3 w-100",
n_clicks=0,
),
html.Div(id="settings-update-trigger", style={"display": "none"}),
html.Span(
id="save-confirmation", style={"verticalAlign": "middle"}
),
dcc.Store(id="settings-store"),
],
style={
@ -221,39 +225,76 @@ class ConfigManager:
return bp
def setup_callbacks(self, app):
# ws = WebSocket(app, url="/ws")
@app.callback(
Output("save-confirmation", "children"),
# Output("settings-store", "data"),
Output("save-confirmation", "children", allow_duplicate=True),
Output("settings-store", "data"),
Input("save-settings", "n_clicks"),
# State({"type": "setting", "key": ALL}, "value"),
# State({"type": "setting", "key": ALL}, "id"),
running=[(Output("save-settings", "disabled"), True, False)],
State({"type": "setting", "key": ALL}, "value"),
State({"type": "setting", "key": ALL}, "id"),
prevent_initial_call=True,
allow_duplicate=True,
# https://github.com/emilhe/dash-extensions/issues/344
# running=[
# (
# Output({
# id: "save-settings",
# 'n_clicks': MATCH
# }, "disabled"), True, False
# )
# ]
)
def save_settings(n_clicks, values, ids):
def save_settings(n_clicks, values, keys):
time.sleep(3)
if n_clicks > 0:
# updated_settings = {}
# print(ids)
# for value, id_dict in zip(values, ids):
# key = id_dict["key"]
# self.update_setting(key.split("-"), value)
# updated_settings[key] = value
updated_settings = {}
return "Настройки сохранены!" # , json.dumps(updated_settings)
return "" # , None
for value, id_dict in zip(values, keys):
key: str = id_dict["key"]
if self._prefix:
key = key.removeprefix(f"{self._prefix}-")
# @app.callback(
# Output({"type": "setting", "key": ALL}, "value"),
# Input("settings-store", "data"),
# )
# def update_settings_from_store(data):
# if data:
# updated_settings = json.loads(data)
# print(
# [current_value for key, current_value in updated_settings.items()]
# )
# return [
# current_value for key, current_value in updated_settings.items()
# ]
# raise dash.exceptions.PreventUpdate()
self.update_setting(key.split("::"), value)
updated_settings[key] = value
import datetime
import locale
locale.setlocale(locale.LC_TIME, "ru_RU.UTF-8")
now = datetime.datetime.now()
date_str = now.strftime("%H:%M:%S")
return (
dbc.Alert(
f"Настройки сохранены в {date_str}",
color="success",
duration=10000,
),
date_str,
)
app.clientside_callback(
"""
function(n_clicks) {
const buttonSelector = '#%s-save-settings';
if (n_clicks > 0) {
document.querySelector(buttonSelector).disabled = true;
}
}
"""
% (self._prefix),
Input("save-settings", "n_clicks"),
)
app.clientside_callback(
"""
function(data) {
const buttonSelector = '#%s-save-settings';
if (data) {
document.querySelector(buttonSelector).disabled = false;
}
}
"""
% (self._prefix),
Input("settings-store", "data"),
)

View File

@ -6,21 +6,11 @@ from .config import config
def register_settings_page():
try:
register_page = get_module("standard.miniapp", "register_page")
#
# def setup_callbacks_wrapper(config_manager):
# def setup(app):
# config_manager.setup_callbacks(app)
#
# return setup
#
# register_page(
# name="Настройки",
# path="/settings",
# layout=config.get_settings_layout(),
# setup_callbacks=setup_callbacks_wrapper(config),
# )
register_page(
name="Настройки", path="/settings", blueprint=config.get_settings_layout()
name="Настройки",
path="/settings",
blueprint=config.get_settings_layout("settings"),
prefix="settings",
)
pass

View File

@ -9,10 +9,11 @@ from flask import Flask
pages = OrderedDict()
def register_page(name, path, blueprint):
def register_page(name, path, blueprint, prefix=""):
pages[path] = {
"name": name,
"blueprint": blueprint,
"prefix": prefix,
}
@ -53,7 +54,7 @@ def create_dash_app(requests_pathname_prefix: str = None) -> dash.Dash:
# Register pages
for path, page in pages.items():
# dash.register_page(page["name"], path=path, layout=page["layout"])
page["blueprint"].register(app, path, prefix="a")
page["blueprint"].register(app, path, prefix=page["prefix"])
# Create sidebar
sidebar = dbc.Offcanvas(
@ -97,7 +98,7 @@ def create_dash_app(requests_pathname_prefix: str = None) -> dash.Dash:
app.layout = html.Div(
[
dcc.Location(id="url", refresh=False),
dcc.Store(id="user-data", storage_type="session"),
# dcc.Store(id="user-data", storage_type="session"),
dcc.Interval(
id="init-telegram-interval",
interval=100,
@ -154,7 +155,7 @@ def create_dash_app(requests_pathname_prefix: str = None) -> dash.Dash:
Input("open-offcanvas", "n_clicks"),
)
# Закрываем offcanvas при клике на ссылку в меню
# # Закрываем offcanvas при клике на ссылку в меню
app.clientside_callback(
"""
function(n_clicks) {