mirror of
https://git.srhtnin.garden/sarah/SaraSort.git
synced 2026-10-14 18:48:11 +02:00
Export and import all of SaraSortd's configs
Settings > SaraSortd can export GlobalConf.toml, both templates and every directory's config as one file, and import it again. An import backs up the current configs first; directories that don't exist can be given a new path (InputDir/OutputDir, ValidInputDirs and the config's own name follow) or made. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
e90f59bc16
commit
60da6dd9ab
4 files changed
+337
-8
No files matched your search
+108
-1
@@ -14,7 +14,9 @@ from Core import (
|
||||
AppConfig, AvailableThemes, BundledFontFamily, ChildEnvironment, ChipButtonStyle, ExportSettings, Home,
|
||||
ImportSettings, LoadSharedSettings, Palette, SharedSettings,
|
||||
)
|
||||
from Widgets import App
|
||||
from Sortd import MajorVersion, Setup, SortdError
|
||||
from SortdTransfer import ApplyBundle, Bundle, BundleDirectories, ExportSortd, MissingDirectories, ReadBundleSafely
|
||||
from Widgets import App, DirField, ExpandPath
|
||||
|
||||
DialogWidth = 700
|
||||
DialogHeight = 520
|
||||
@@ -108,6 +110,32 @@ def ShowSettingsDialog(TheApp: App, OnSaved: Callable[[], None]) -> None:
|
||||
RefreshField = _NumberField("Service page refresh (seconds)", Config.RefreshSeconds)
|
||||
LogLinesField = _NumberField("Log lines to show", Config.LogLines)
|
||||
|
||||
SortdFileField = ft.TextField(value=str(Home / "SaraSortd-Configs.toml"), label="SaraSortd export file path")
|
||||
|
||||
def OnSortdExport(e) -> None:
|
||||
PathText = (SortdFileField.value or "").strip()
|
||||
if not PathText:
|
||||
return
|
||||
try:
|
||||
Count = ExportSortd(Config, Path(PathText).expanduser())
|
||||
except (OSError, SortdError) as Error:
|
||||
TheApp.Notify(f"Couldn't export SaraSortd's configs: {Error}", "error")
|
||||
return
|
||||
TheApp.Notify(f"Exported {Count} SaraSortd configs.", "success")
|
||||
|
||||
def OnSortdImport(e) -> None:
|
||||
PathText = (SortdFileField.value or "").strip()
|
||||
if not PathText:
|
||||
return
|
||||
TheBundle, Error = ReadBundleSafely(Path(PathText).expanduser())
|
||||
if TheBundle is None:
|
||||
TheApp.Notify(Error, "error")
|
||||
return
|
||||
# Same as importing SaraSort's own settings: the Settings dialog
|
||||
# closes, so a stale Save can't undo what the import wrote.
|
||||
Page.pop_dialog()
|
||||
ShowSortdImportDialog(TheApp, TheBundle, OnSaved)
|
||||
|
||||
def OnExport(e) -> None:
|
||||
PathText = (SettingsFileField.value or "").strip()
|
||||
if not PathText:
|
||||
@@ -177,6 +205,15 @@ def ShowSettingsDialog(TheApp: App, OnSaved: Callable[[], None]) -> None:
|
||||
ft.Divider(height=1, color=Palette.Surface1),
|
||||
RefreshField,
|
||||
LogLinesField,
|
||||
ft.Divider(height=1, color=Palette.Surface1),
|
||||
_Note("Export/import all of SaraSortd's configs as one file: GlobalConf.toml, both templates "
|
||||
"and every input/output directory's own config. Importing replaces the current ones "
|
||||
"(they're backed up first)."),
|
||||
SortdFileField,
|
||||
ft.Row([
|
||||
ft.OutlinedButton(content="Export", style=ChipButtonStyle(), on_click=OnSortdExport),
|
||||
ft.OutlinedButton(content="Import", style=ChipButtonStyle(), on_click=OnSortdImport),
|
||||
]),
|
||||
],
|
||||
spacing=12,
|
||||
scroll=ft.ScrollMode.AUTO,
|
||||
@@ -251,3 +288,73 @@ def ShowSettingsDialog(TheApp: App, OnSaved: Callable[[], None]) -> None:
|
||||
ft.OutlinedButton(content="Save", style=ChipButtonStyle(), on_click=Save),
|
||||
],
|
||||
))
|
||||
|
||||
|
||||
def ShowSortdImportDialog(TheApp: App, TheBundle: Bundle, OnDone: Callable[[], None]) -> None:
|
||||
"""Confirms a SaraSortd import. Directories it uses that don't exist are
|
||||
listed with a path field each: keep the path to have it made, or change it
|
||||
to use another directory instead."""
|
||||
Page = TheApp.Page
|
||||
Config = TheApp.Config
|
||||
try:
|
||||
Missing = MissingDirectories(Config, TheBundle)
|
||||
Total = len(BundleDirectories(Config, TheBundle))
|
||||
except Exception as Error: # e.g. a GlobalConf in the export without the keys SaraSortd needs
|
||||
TheApp.Notify(f"Can't use that export: {Error}", "error")
|
||||
return
|
||||
|
||||
Fields: dict[str, ft.TextField] = {}
|
||||
Rows: list[ft.Control] = []
|
||||
for DirPath in Missing:
|
||||
Row, Field = DirField(TheApp, f"{Path(DirPath).name or DirPath} (doesn't exist)", DirPath)
|
||||
Fields[DirPath] = Field
|
||||
Rows.append(Row)
|
||||
|
||||
Info = [
|
||||
_Note(f"From an export of SaraSortd {TheBundle.SortdVersion or '?'}"
|
||||
+ (f", made {TheBundle.Exported.replace('T', ' ')}" if TheBundle.Exported else "") + "."),
|
||||
ft.Text(f"This replaces SaraSortd's configs in {Config.SortdConfigDir} and in {Total} "
|
||||
f"director{'y' if Total == 1 else 'ies'}. The current ones are backed up to "
|
||||
"~/.config/SaraSuite/SaraSort/Backups/ first.", size=13),
|
||||
]
|
||||
try:
|
||||
Daemon = Setup(Config).DaemonVersion()
|
||||
except SortdError:
|
||||
Daemon = None
|
||||
if Daemon and TheBundle.SortdVersion and MajorVersion(Daemon) != MajorVersion(TheBundle.SortdVersion):
|
||||
Info.append(ft.Text(f"These configs are from SaraSortd {TheBundle.SortdVersion}, but {Daemon} is installed: "
|
||||
"the first number differs, so they may not work.", color=Palette.Red, size=13))
|
||||
if Missing:
|
||||
Info += [
|
||||
ft.Divider(height=1, color=Palette.Surface1),
|
||||
ft.Row([ft.Icon(ft.Icons.WARNING_AMBER, color=Palette.Yellow),
|
||||
ft.Text(f"{len(Missing)} director{'y' if len(Missing) == 1 else 'ies'} "
|
||||
f"{'doesn' if len(Missing) == 1 else 'don'}'t exist:", color=Palette.Yellow)]),
|
||||
_Note("Keep a path to have it made, or change it to use another directory instead "
|
||||
"(the configs and arrows follow it)."),
|
||||
# Only the list scrolls, so the dialog stays as small as its content.
|
||||
ft.Column(Rows, spacing=8, scroll=ft.ScrollMode.AUTO, height=min(300, 58 * len(Rows))),
|
||||
]
|
||||
|
||||
def Continue(e) -> None:
|
||||
Remap = {Old: ExpandPath(Field.value or "") or Old for Old, Field in Fields.items()}
|
||||
Page.pop_dialog()
|
||||
try:
|
||||
ApplyBundle(Config, TheBundle, Remap)
|
||||
except (OSError, SortdError) as Error:
|
||||
TheApp.Notify(f"Import failed: {Error}", "error")
|
||||
return
|
||||
OnDone()
|
||||
TheApp.AfterGlobalChange() # its toast says whether SaraSortd restarted
|
||||
|
||||
Page.show_dialog(ft.AlertDialog(
|
||||
title="Import SaraSortd configs",
|
||||
content=ft.Column(Info, width=620, tight=True, spacing=10),
|
||||
actions=[
|
||||
ft.OutlinedButton(content="Cancel", style=ChipButtonStyle(), on_click=lambda e: Page.pop_dialog()),
|
||||
ft.OutlinedButton(
|
||||
content="Make directories and import" if Missing else "Import",
|
||||
style=ChipButtonStyle(Palette.Yellow if Missing else ""), on_click=Continue,
|
||||
),
|
||||
],
|
||||
))
|
||||
Reference in new issue
Block a user