Компактный диалог операции и кнопки, которые не уезжают
Пары Switch + Label заменены на Checkbox с встроенной подписью: строка вместо трёх. Поля стали однострочными, чекбоксы дампа встали в ряд, заголовок и имя базы слились в одну строку — диалог ужался с почти целого экрана до 17-18 строк на любом размере консоли. Ряд кнопок пропадал потому, что .dialog с height: auto складывал высоту детей и упирался в max-height, обрезая нижнюю строку. Теперь у диалога операции своя высота, а форма забирает остаток через height: 1fr и скроллится сама. Диалог restore приведён к тому же виду.
This commit is contained in:
+59
-57
@@ -25,8 +25,8 @@ from textual.content import Content
|
||||
from textual.message import Message
|
||||
from textual.screen import ModalScreen, Screen
|
||||
from textual.theme import Theme
|
||||
from textual.widgets import (Button, Collapsible, Footer, Input, Label, OptionList,
|
||||
ProgressBar, RichLog, Static, Switch)
|
||||
from textual.widgets import (Button, Checkbox, Collapsible, Footer, Input, Label,
|
||||
OptionList, ProgressBar, RichLog, Static)
|
||||
from textual.widgets.option_list import Option
|
||||
from textual.worker import WorkerState, get_current_worker
|
||||
|
||||
@@ -334,16 +334,16 @@ class ConfirmModal(ModalScreen):
|
||||
yield Static("локальные базы — как на стенде (выбрано несколько)",
|
||||
classes="subject")
|
||||
else:
|
||||
yield Label("локальная база")
|
||||
yield Input(value=self.spec.target_db, id="target")
|
||||
with Horizontal(classes="switch-row"):
|
||||
yield Switch(value=self.recreate, id="recreate")
|
||||
yield Label("пересоздать (DROP + CREATE)")
|
||||
with Horizontal(classes="field"):
|
||||
yield Label("локальная база", classes="inline")
|
||||
yield Input(value=self.spec.target_db, id="target", compact=True)
|
||||
yield Checkbox("пересоздать (DROP + CREATE)", value=self.recreate,
|
||||
id="recreate", compact=True)
|
||||
yield Static(self._danger_text(), id="danger",
|
||||
classes="danger" + ("" if self.recreate else " hidden"))
|
||||
with Horizontal(classes="row"):
|
||||
yield Button("Отмена", id="cancel")
|
||||
yield Button("Начать", variant="success", id="start")
|
||||
yield Button("Отмена", id="cancel", compact=True)
|
||||
yield Button("Начать", variant="success", id="start", compact=True)
|
||||
|
||||
def on_mount(self) -> None:
|
||||
# повторяет умолчание confirm_target: при recreate=true согласие не подразумевается
|
||||
@@ -355,7 +355,7 @@ class ConfirmModal(ModalScreen):
|
||||
return (f"локальная база {name} будет удалена (DROP DATABASE) и создана заново — "
|
||||
f"её текущее содержимое пропадёт")
|
||||
|
||||
def on_switch_changed(self, event: Switch.Changed) -> None:
|
||||
def on_checkbox_changed(self, event: Checkbox.Changed) -> None:
|
||||
self.query_one("#danger", Static).set_class(not event.value, "hidden")
|
||||
|
||||
def on_input_submitted(self) -> None:
|
||||
@@ -376,7 +376,7 @@ class ConfirmModal(ModalScreen):
|
||||
self.notify("имя локальной базы пустое", severity="error")
|
||||
return
|
||||
self.spec.target_db = value
|
||||
self.spec.no_recreate = not self.query_one("#recreate", Switch).value
|
||||
self.spec.no_recreate = not self.query_one("#recreate", Checkbox).value
|
||||
self.dismiss(self.spec)
|
||||
|
||||
def action_cancel(self) -> None:
|
||||
@@ -414,55 +414,57 @@ class DbOpModal(ModalScreen):
|
||||
self.target_db = None if len(dbs) > 1 else (configured or dbs[0])
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with Vertical(classes="dialog"):
|
||||
yield Static("Операция с базой", classes="title")
|
||||
yield Static(", ".join(self.dbs), classes="subject")
|
||||
# Checkbox вместо пары Switch+Label: подпись встроена, строка вместо трёх
|
||||
with Vertical(classes="dialog op-dialog"):
|
||||
yield Static(f"Операция с базой · {', '.join(self.dbs)}", classes="title")
|
||||
with VerticalScroll(classes="form"):
|
||||
with Horizontal(classes="switch-row"):
|
||||
yield Switch(value=self.autorestore, id="autorestore")
|
||||
yield Label("поднять на локальной PG сразу после дампа")
|
||||
|
||||
yield Checkbox("поднять на локальной PG сразу после дампа",
|
||||
value=self.autorestore, id="autorestore", compact=True)
|
||||
yield Static("Дамп", classes="section")
|
||||
for wid, label, key in (("schema-only", "только схема, без данных", "schema_only"),
|
||||
("no-owner", "без владельцев (--no-owner)", "no_owner"),
|
||||
("no-priv", "без прав (--no-privileges)", "no_privileges")):
|
||||
with Horizontal(classes="switch-row"):
|
||||
yield Switch(value=bool(self.dump_opts.get(key, key != "schema_only")),
|
||||
id=wid)
|
||||
yield Label(label)
|
||||
yield Label("сжатие 0–9")
|
||||
yield Input(value=str(self.dump_opts.get("compress", 6)), id="compress")
|
||||
yield Checkbox("только схема, без данных",
|
||||
value=bool(self.dump_opts.get("schema_only", False)),
|
||||
id="schema-only", compact=True)
|
||||
with Horizontal(classes="check-row"):
|
||||
yield Checkbox("без владельцев",
|
||||
value=bool(self.dump_opts.get("no_owner", True)),
|
||||
id="no-owner", compact=True)
|
||||
yield Checkbox("без прав",
|
||||
value=bool(self.dump_opts.get("no_privileges", True)),
|
||||
id="no-priv", compact=True)
|
||||
yield Label("сжатие", classes="inline")
|
||||
yield Input(value=str(self.dump_opts.get("compress", 6)), id="compress",
|
||||
compact=True, classes="num")
|
||||
with Collapsible(title="состав дампа", collapsed=True):
|
||||
yield Label("только схемы (через запятую)")
|
||||
yield Input(value=_csv(self.dump_opts.get("schemas")), id="schemas")
|
||||
yield Label("исключить схемы")
|
||||
yield Input(value=_csv(self.dump_opts.get("exclude_schemas")),
|
||||
id="ex-schemas")
|
||||
yield Label("исключить таблицы")
|
||||
yield Input(value=_csv(self.dump_opts.get("exclude_tables")),
|
||||
id="ex-tables")
|
||||
yield Label("исключить только данные таблиц")
|
||||
yield Input(value=_csv(self.dump_opts.get("exclude_table_data")),
|
||||
id="ex-data")
|
||||
for wid, label, key in (
|
||||
("schemas", "только схемы", "schemas"),
|
||||
("ex-schemas", "исключить схемы", "exclude_schemas"),
|
||||
("ex-tables", "исключить таблицы", "exclude_tables"),
|
||||
("ex-data", "исключить данные таблиц", "exclude_table_data")):
|
||||
with Horizontal(classes="field"):
|
||||
yield Label(label, classes="inline")
|
||||
yield Input(value=_csv(self.dump_opts.get(key)), id=wid,
|
||||
compact=True, placeholder="через запятую")
|
||||
|
||||
with Vertical(id="target-block",
|
||||
classes="" if self.autorestore else "hidden"):
|
||||
yield Static("Локальная база", classes="section")
|
||||
if self.target_db is None:
|
||||
yield Static("каждая база — в одноимённую локальную", classes="subject")
|
||||
else:
|
||||
yield Label("имя")
|
||||
yield Input(value=self.target_db, id="target")
|
||||
with Horizontal(classes="switch-row"):
|
||||
yield Switch(value=self.recreate, id="recreate")
|
||||
yield Label("пересоздать (DROP + CREATE)")
|
||||
yield Label("параллельных воркеров restore")
|
||||
yield Input(value=str(self.restore_opts.get("jobs", 4)), id="jobs")
|
||||
with Horizontal(classes="field"):
|
||||
if self.target_db is None:
|
||||
yield Label("каждая база — в одноимённую локальную", classes="inline")
|
||||
else:
|
||||
yield Label("имя", classes="inline")
|
||||
yield Input(value=self.target_db, id="target", compact=True)
|
||||
with Horizontal(classes="check-row"):
|
||||
yield Checkbox("пересоздать (DROP + CREATE)", value=self.recreate,
|
||||
id="recreate", compact=True)
|
||||
yield Label("воркеров", classes="inline")
|
||||
yield Input(value=str(self.restore_opts.get("jobs", 4)), id="jobs",
|
||||
compact=True, classes="num")
|
||||
yield Static(self._danger_text(), id="danger",
|
||||
classes="danger" + ("" if self.recreate else " hidden"))
|
||||
with Horizontal(classes="row"):
|
||||
yield Button("Отмена", id="cancel")
|
||||
yield Button("Начать", variant="success", id="start")
|
||||
yield Button("Отмена", id="cancel", compact=True)
|
||||
yield Button("Начать", variant="success", id="start", compact=True)
|
||||
|
||||
def on_mount(self) -> None:
|
||||
# согласие на DROP не подразумевается: фокус на «Отмена», пока база пересоздаётся
|
||||
@@ -474,11 +476,11 @@ class DbOpModal(ModalScreen):
|
||||
return (f"локальная база {name} будет удалена (DROP DATABASE) и создана заново — "
|
||||
f"её текущее содержимое пропадёт")
|
||||
|
||||
def on_switch_changed(self, event: Switch.Changed) -> None:
|
||||
if event.switch.id == "autorestore":
|
||||
def on_checkbox_changed(self, event: Checkbox.Changed) -> None:
|
||||
if event.checkbox.id == "autorestore":
|
||||
self.autorestore = event.value
|
||||
self.query_one("#target-block").set_class(not event.value, "hidden")
|
||||
elif event.switch.id == "recreate":
|
||||
elif event.checkbox.id == "recreate":
|
||||
self.recreate = event.value
|
||||
self.query_one("#danger", Static).set_class(not event.value, "hidden")
|
||||
|
||||
@@ -509,9 +511,9 @@ class DbOpModal(ModalScreen):
|
||||
if compress is None:
|
||||
return
|
||||
dump_opts = {
|
||||
"schema_only": self.query_one("#schema-only", Switch).value,
|
||||
"no_owner": self.query_one("#no-owner", Switch).value,
|
||||
"no_privileges": self.query_one("#no-priv", Switch).value,
|
||||
"schema_only": self.query_one("#schema-only", Checkbox).value,
|
||||
"no_owner": self.query_one("#no-owner", Checkbox).value,
|
||||
"no_privileges": self.query_one("#no-priv", Checkbox).value,
|
||||
"compress": compress,
|
||||
"schemas": _split_csv(self.query_one("#schemas", Input).value),
|
||||
"exclude_schemas": _split_csv(self.query_one("#ex-schemas", Input).value),
|
||||
@@ -526,7 +528,7 @@ class DbOpModal(ModalScreen):
|
||||
if jobs is None:
|
||||
return
|
||||
overrides["restore"] = {"jobs": jobs}
|
||||
no_recreate = not self.query_one("#recreate", Switch).value
|
||||
no_recreate = not self.query_one("#recreate", Checkbox).value
|
||||
if self.target_db is not None:
|
||||
target_db = self.query_one("#target", Input).value.strip()
|
||||
if not target_db:
|
||||
|
||||
Reference in New Issue
Block a user