Replace schedule source/destination lists with toggle switches, add DOCUMENTATION.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
shuki
2026-03-07 05:04:45 +02:00
parent 3ba8c6b715
commit a362ec7589
3 changed files with 1112 additions and 32 deletions

1066
DOCUMENTATION.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -395,6 +395,18 @@ Switch {
margin: 0 1; margin: 0 1;
} }
.sched-switch-row {
height: 3;
align: left middle;
margin: 0;
}
.sched-switch-label {
width: 1fr;
height: 3;
content-align: left middle;
}
.section-label { .section-label {
text-style: bold; text-style: bold;
color: #00cc00; color: #00cc00;

View File

@@ -1,7 +1,7 @@
import re import re
from textual.app import ComposeResult from textual.app import ComposeResult
from textual.screen import Screen from textual.screen import Screen
from textual.widgets import Header, Footer, Static, Button, Input, Select, SelectionList from textual.widgets import Header, Footer, Static, Button, Input, Select, SelectionList, Switch
from tui.widgets.header import GnizaHeader as Header # noqa: F811 from tui.widgets.header import GnizaHeader as Header # noqa: F811
from textual.containers import Vertical, Horizontal from textual.containers import Vertical, Horizontal
@@ -105,27 +105,29 @@ class ScheduleEditScreen(Screen):
placeholder="0 2 * * *", placeholder="0 2 * * *",
classes="sched-cron-field", classes="sched-cron-field",
) )
yield Static("Sources (empty=all):") yield Static("Sources (off=all):")
yield SelectionList[str]( for tname in list_conf_dir("targets.d"):
*self._build_target_choices(), with Horizontal(classes="sched-switch-row"):
id="sched-targets", yield Static(tname, classes="sched-switch-label")
) yield Switch(value=False, id=f"sched-src-{tname}")
yield Static("Destinations (empty=all):") yield Static("Destinations (off=all):")
yield SelectionList[str]( for rname in list_conf_dir("remotes.d"):
*self._build_remote_choices(), with Horizontal(classes="sched-switch-row"):
id="sched-remotes", yield Static(rname, classes="sched-switch-label")
) yield Switch(value=False, id=f"sched-dst-{rname}")
with Horizontal(id="sched-edit-buttons"): with Horizontal(id="sched-edit-buttons"):
yield Button("Save", variant="primary", id="btn-save") yield Button("Save", variant="primary", id="btn-save")
yield Button("Cancel", id="btn-cancel") yield Button("Cancel", id="btn-cancel")
yield DocsPanel.for_screen("schedule-edit") yield DocsPanel.for_screen("schedule-edit")
yield Footer() yield Footer()
def _build_target_choices(self) -> list[tuple[str, str]]: def _get_selected_switches(self, prefix: str) -> list[str]:
return [(name, name) for name in list_conf_dir("targets.d")] """Return names of enabled switches matching the ID prefix."""
selected = []
def _build_remote_choices(self) -> list[tuple[str, str]]: for sw in self.query(Switch):
return [(name, name) for name in list_conf_dir("remotes.d")] if sw.id and sw.id.startswith(prefix) and sw.value:
selected.append(sw.id[len(prefix):])
return selected
def on_mount(self) -> None: def on_mount(self) -> None:
self._update_type_visibility() self._update_type_visibility()
@@ -144,22 +146,22 @@ class ScheduleEditScreen(Screen):
opt = days_list.get_option_at_index(idx) opt = days_list.get_option_at_index(idx)
if opt.value in day_vals: if opt.value in day_vals:
days_list.select(opt.value) days_list.select(opt.value)
# Targets # Sources
if sched.targets: if sched.targets:
target_vals = set(sched.targets.split(",")) for tname in sched.targets.split(","):
tlist = self.query_one("#sched-targets", SelectionList) tname = tname.strip()
for idx in range(tlist.option_count): try:
opt = tlist.get_option_at_index(idx) self.query_one(f"#sched-src-{tname}", Switch).value = True
if opt.value in target_vals: except Exception:
tlist.select(opt.value) pass
# Remotes # Destinations
if sched.remotes: if sched.remotes:
remote_vals = set(sched.remotes.split(",")) for rname in sched.remotes.split(","):
rlist = self.query_one("#sched-remotes", SelectionList) rname = rname.strip()
for idx in range(rlist.option_count): try:
opt = rlist.get_option_at_index(idx) self.query_one(f"#sched-dst-{rname}", Switch).value = True
if opt.value in remote_vals: except Exception:
rlist.select(opt.value) pass
def on_select_changed(self, event: Select.Changed) -> None: def on_select_changed(self, event: Select.Changed) -> None:
if event.select.id == "sched-type": if event.select.id == "sched-type":
@@ -226,8 +228,8 @@ class ScheduleEditScreen(Screen):
time=self.query_one("#sched-time", Input).value.strip() or "02:00", time=self.query_one("#sched-time", Input).value.strip() or "02:00",
day=day_val, day=day_val,
cron=self.query_one("#sched-cron", Input).value.strip(), cron=self.query_one("#sched-cron", Input).value.strip(),
targets=",".join(self.query_one("#sched-targets", SelectionList).selected), targets=",".join(self._get_selected_switches("sched-src-")),
remotes=",".join(self.query_one("#sched-remotes", SelectionList).selected), remotes=",".join(self._get_selected_switches("sched-dst-")),
) )
conf = CONFIG_DIR / "schedules.d" / f"{name}.conf" conf = CONFIG_DIR / "schedules.d" / f"{name}.conf"
write_conf(conf, sched.to_conf()) write_conf(conf, sched.to_conf())