Compare commits

...
2 Commits
5 changed files with 137 additions and 15 deletions

No files matched your search

@@ -76,7 +76,7 @@ class MainsailThemeInstallerExtension(BaseExtension):
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
class MainsailThemeInstallMenu(BaseMenu): class MainsailThemeInstallMenu(BaseMenu):
THEMES_URL: str = ( THEMES_URL: str = (
"https://raw.githubusercontent.com/mainsail-crew/gb-docs/main/_data/themes.csv" "https://raw.githubusercontent.com/mainsail-crew/docs/zensical/_data/themes.csv"
) )
def __init__(self, instances: List[Klipper]): def __init__(self, instances: List[Klipper]):
@@ -94,8 +94,9 @@ class MainsailThemeInstallMenu(BaseMenu):
) )
def set_options(self) -> None: def set_options(self) -> None:
# Menu numbers start at 1 to match the theme IDs on the Mainsail docs page
self.options = { self.options = {
f"{index}": Option(self.install_theme, opt_index=f"{index}") f"{index + 1}": Option(self.install_theme, opt_index=f"{index}")
for index in range(len(self.themes)) for index in range(len(self.themes))
} }
@@ -107,11 +108,12 @@ class MainsailThemeInstallMenu(BaseMenu):
f""" f"""
╟───────────────────────────────────────────────────────╢ ╟───────────────────────────────────────────────────────╢
║ {line1:<62} ║ ║ {line1:<62} ║
║ https://docs.mainsail.xyz/theming/themes ║ ║ https://docs.mainsail.xyz/features/custom- ║
║ themes/community-themes/ ║
╟───────────────────────────────────────────────────────╢ ╟───────────────────────────────────────────────────────╢
""" """
)[1:] )[1:]
for i, theme in enumerate(self.themes): for i, theme in enumerate(self.themes, start=1):
j: str = f" {i}" if i < 10 else f"{i}" j: str = f" {i}" if i < 10 else f"{i}"
row: str = f"{j}) [{theme.name}]" row: str = f"{j}) [{theme.name}]"
menu += f"║ {row:<53} ║\n" menu += f"║ {row:<53} ║\n"
@@ -123,12 +125,19 @@ class MainsailThemeInstallMenu(BaseMenu):
themes: List[ThemeData] = [] themes: List[ThemeData] = []
content: str = response.read().decode() content: str = response.read().decode()
csv_data: List[str] = content.splitlines() csv_data: List[str] = content.splitlines()
fieldnames = ["name", "short_note", "author", "repo"] # read columns by the csv header, so extra columns in the list
csv_reader = csv.DictReader(csv_data, fieldnames=fieldnames, delimiter=",") # (e.g. "branch" and "preview", used by the docs page) are ignored
next(csv_reader) # skip the header of the csv file csv_reader = csv.DictReader(csv_data, delimiter=",")
for row in csv_reader: for row in csv_reader:
row: Dict[str, str] # type: ignore row: Dict[str, str] # type: ignore
theme: ThemeData = ThemeData(**row) if not row.get("author") or not row.get("repo"):
continue
theme: ThemeData = ThemeData(
name=row.get("name") or row["repo"],
short_note=row.get("short_note") or "",
author=row["author"],
repo=row["repo"],
)
themes.append(theme) themes.append(theme)
return themes return themes
@@ -5,7 +5,7 @@
"maintained_by": "dw-0", "maintained_by": "dw-0",
"display_name": "Mainsail Theme Installer", "display_name": "Mainsail Theme Installer",
"description": ["Install Mainsail Themes maintained by the Mainsail community."], "description": ["Install Mainsail Themes maintained by the Mainsail community."],
"website": "https://docs.mainsail.xyz/theming/themes", "website": "https://docs.mainsail.xyz/features/custom-themes/community-themes/",
"updates": false "updates": false
} }
} }
+2 -3
View File
@@ -5,9 +5,8 @@
"maintained_by": "PEEKYPAUL", "maintained_by": "PEEKYPAUL",
"display_name": "Moongate for Klipper", "display_name": "Moongate for Klipper",
"description": [ "description": [
"Pair this printer with the Moongate Android app for secure remote", "Pair this printer with the Moongate app on Android or iPhone for secure remote access and print monitoring.",
"access and print monitoring. Installs cloudflared, a Cloudflare", "Installs cloudflared, a Cloudflare quick-tunnel and an EdDSA auth gate in front of Moonraker."
"quick-tunnel and an EdDSA auth gate in front of Moonraker."
], ],
"repo": "https://github.com/PEEKYPAUL/Moongate", "repo": "https://github.com/PEEKYPAUL/Moongate",
"updates": true "updates": true
@@ -134,7 +134,8 @@ class MoongateExtension(BaseExtension):
"Moongate installed successfully!", "Moongate installed successfully!",
"\n\n", "\n\n",
"Next steps:", "Next steps:",
"● Install the Moongate app on your Android device.", "● Install the Moongate app on your phone (Google Play for "
"Android, the App Store for iPhone).",
( (
"● In the app: Add printer > Direct (LAN/VPN), then run " "● In the app: Add printer > Direct (LAN/VPN), then run "
"MOONGATE_PAIR in the Klipper console and scan the QR (or " "MOONGATE_PAIR in the Klipper console and scan the QR (or "
@@ -224,8 +225,8 @@ class MoongateExtension(BaseExtension):
Logger.print_dialog( Logger.print_dialog(
DialogType.ATTENTION, DialogType.ATTENTION,
[ [
"Moongate pairs this printer with the Moongate Android app for " "Moongate pairs this printer with the Moongate app on Android or "
"secure remote access and print monitoring.", "iPhone for secure remote access and print monitoring.",
"\n\n", "\n\n",
"This is a heavier install than most extensions. It will:", "This is a heavier install than most extensions. It will:",
"● clone the Moongate repo to ~/moongate", "● clone the Moongate repo to ~/moongate",
@@ -0,0 +1,113 @@
# ======================================================================= #
# Copyright (C) 2020 - 2026 Dominik Willner <dev.dw-0@proton.me> #
# #
# This file is part of KIAUH - Klipper Installation And Update Helper #
# https://github.com/dw-0/kiauh #
# #
# This file may be distributed under the terms of the GNU GPLv3 license #
# ======================================================================= #
from __future__ import annotations
import pytest
from extensions.mainsail_theme_installer.mainsail_theme_installer_extension import (
MainsailThemeInstallMenu,
ThemeData,
)
MODULE = "extensions.mainsail_theme_installer.mainsail_theme_installer_extension"
# current format of the list in mainsail-crew/docs
DOCS_CSV = (
"name,short_note,author,repo,branch,preview\n"
"Dracula,,steadyjaw,dracula-mainsail-theme,master,screenshot.jpg\n"
"Printables,(unofficial),8bitmcu,mainsail-printables,main,screenshot.jpg\n"
)
# legacy format of the list in mainsail-crew/gb-docs
LEGACY_CSV = (
"name,short_note,author,repo\n"
"Dracula,,steadyjaw,dracula-mainsail-theme\n"
"Printables,(unofficial),8bitmcu,mainsail-printables\n"
)
EXPECTED_THEMES = [
ThemeData("Dracula", "", "steadyjaw", "dracula-mainsail-theme"),
ThemeData("Printables", "(unofficial)", "8bitmcu", "mainsail-printables"),
]
class _FakeResponse:
def __init__(self, body: str) -> None:
self._body = body.encode()
def __enter__(self):
return self
def __exit__(self, *args):
return None
def read(self) -> bytes:
return self._body
def _patch_themes_csv(monkeypatch: pytest.MonkeyPatch, body: str) -> None:
class FakeUrlLib:
@staticmethod
def urlopen(url: str):
return _FakeResponse(body)
monkeypatch.setattr(f"{MODULE}.urllib.request", FakeUrlLib())
@pytest.fixture
def menu(monkeypatch: pytest.MonkeyPatch) -> MainsailThemeInstallMenu:
_patch_themes_csv(monkeypatch, DOCS_CSV)
return MainsailThemeInstallMenu([])
class TestLoadThemes:
def test_parses_docs_format_and_ignores_extra_columns(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
_patch_themes_csv(monkeypatch, DOCS_CSV)
assert MainsailThemeInstallMenu([]).themes == EXPECTED_THEMES
def test_parses_legacy_format(self, monkeypatch: pytest.MonkeyPatch) -> None:
_patch_themes_csv(monkeypatch, LEGACY_CSV)
assert MainsailThemeInstallMenu([]).themes == EXPECTED_THEMES
def test_skips_blank_and_incomplete_rows(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
_patch_themes_csv(monkeypatch, DOCS_CSV + "\n" + "Broken,,,,,\n")
assert MainsailThemeInstallMenu([]).themes == EXPECTED_THEMES
class TestThemeMenuNumbering:
def test_options_start_at_one_to_match_docs_ids(
self, menu: MainsailThemeInstallMenu
) -> None:
menu.set_options()
assert list(menu.options) == ["1", "2"]
assert menu.options["1"].opt_index == "0"
assert menu.options["2"].opt_index == "1"
def test_menu_lists_themes_from_one(
self, menu: MainsailThemeInstallMenu, capsys
) -> None:
menu.print_menu()
out = capsys.readouterr().out
assert " 1) [Dracula]" in out
assert " 2) [Printables]" in out
assert " 0) [" not in out
def test_menu_links_to_current_docs(
self, menu: MainsailThemeInstallMenu, capsys
) -> None:
menu.print_menu()
out = capsys.readouterr().out
# the url is too long for the menu box, so it is wrapped over two lines
assert "║ https://docs.mainsail.xyz/features/custom- ║" in out
assert "║ themes/community-themes/ ║" in out
assert "theming/themes" not in out