fix: three mobile/WSL bugs reported by tester
- Mobile idle tiles: display:none → height:36px so session content is visible (all sessions are 'idle' with zero bells — was blank on iPhone) - .tile-pre dead CSS: merge font/color rules into .tile-body pre (the actual HTML selector) so snapshot text renders with monospace + muted color; update mobile active-tier selector to match - systemd PATH: strip /mnt/ entries from PATH before writing service unit file — WSL paths with spaces caused systemd to reject the line
This commit is contained in:
+5
-1
@@ -25,6 +25,10 @@ def install_service(*, system: bool = False) -> None:
|
||||
"""Install muxplex as a systemd service."""
|
||||
executable = sys.executable
|
||||
|
||||
_raw_path = os.environ.get("PATH", "/usr/local/bin:/usr/bin:/bin")
|
||||
_safe_path = ":".join(p for p in _raw_path.split(":") if not p.startswith("/mnt/"))
|
||||
_safe_path = _safe_path or "/usr/local/bin:/usr/bin:/bin"
|
||||
|
||||
unit = f"""\
|
||||
[Unit]
|
||||
Description=muxplex — web-based tmux session dashboard
|
||||
@@ -35,7 +39,7 @@ Type=simple
|
||||
ExecStart={executable} -m muxplex
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
Environment=PATH={os.environ.get("PATH", "/usr/local/bin:/usr/bin:/bin")}
|
||||
Environment=PATH={_safe_path}
|
||||
|
||||
[Install]
|
||||
WantedBy={"multi-user.target" if system else "default.target"}
|
||||
|
||||
@@ -228,6 +228,13 @@ body {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 6px 8px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
color: var(--text-dim);
|
||||
white-space: pre;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tile-pre {
|
||||
@@ -678,15 +685,15 @@ body {
|
||||
.session-tile--tier-active {
|
||||
min-height: 60px;
|
||||
}
|
||||
.session-tile--tier-active .tile-pre {
|
||||
.session-tile--tier-active .tile-body pre {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Tier 3 — idle: name-only (~44px total) */
|
||||
/* Tier 3 — idle: compact preview (36px body) */
|
||||
.session-tile--tier-idle .tile-body {
|
||||
display: none;
|
||||
height: 36px;
|
||||
}
|
||||
.session-tile--tier-idle {
|
||||
min-height: 44px;
|
||||
|
||||
@@ -84,6 +84,43 @@ def test_install_service_system_mode_target(tmp_path, monkeypatch):
|
||||
assert "multi-user.target" in content
|
||||
|
||||
|
||||
def test_install_service_strips_wsl_mnt_paths_from_environment(tmp_path, monkeypatch):
|
||||
"""Fix 3: install_service() must strip /mnt/ paths from Environment=PATH.
|
||||
|
||||
WSL mounts Windows at /mnt/c/, /mnt/d/ etc. Paths like
|
||||
'/mnt/c/Program Files/dotnet/' contain spaces, causing systemd to
|
||||
truncate and reject the Environment= line.
|
||||
"""
|
||||
from muxplex.cli import install_service
|
||||
|
||||
fake_home = tmp_path / "home"
|
||||
fake_home.mkdir()
|
||||
monkeypatch.setattr(Path, "home", staticmethod(lambda: fake_home))
|
||||
|
||||
wsl_path = (
|
||||
"/usr/local/bin:/usr/bin:/bin:/mnt/c/Program Files/dotnet:/mnt/d/tools/bin"
|
||||
)
|
||||
monkeypatch.setenv("PATH", wsl_path)
|
||||
|
||||
install_service(system=False)
|
||||
|
||||
unit_path = fake_home / ".config" / "systemd" / "user" / "muxplex.service"
|
||||
content = unit_path.read_text()
|
||||
|
||||
# Find the Environment=PATH line
|
||||
env_line = next(
|
||||
(line for line in content.splitlines() if line.startswith("Environment=PATH=")),
|
||||
None,
|
||||
)
|
||||
assert env_line is not None, "Environment=PATH line must be present"
|
||||
assert "/mnt/" not in env_line, (
|
||||
f"WSL /mnt/ paths must be stripped from Environment=PATH; got: {env_line!r}"
|
||||
)
|
||||
# Safe paths must still be present
|
||||
assert "/usr/local/bin" in env_line
|
||||
assert "/usr/bin" in env_line
|
||||
|
||||
|
||||
def test_dunder_main_calls_main():
|
||||
"""python -m muxplex must call cli.main()."""
|
||||
import importlib.util
|
||||
|
||||
@@ -534,3 +534,56 @@ def test_css_reduced_motion_sidebar_after_toast():
|
||||
assert toast_idx < sidebar_idx, (
|
||||
".session-sidebar must come after .toast in reduced-motion block"
|
||||
)
|
||||
|
||||
|
||||
# ── Bug-fix regression tests ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_idle_tile_body_not_display_none():
|
||||
"""Fix 1: .session-tile--tier-idle .tile-body must NOT use display:none.
|
||||
|
||||
All sessions are 'idle' when zero bell notifications — display:none caused
|
||||
a blank screen on mobile (iPhone).
|
||||
"""
|
||||
css = read_css()
|
||||
# Locate the idle rule block
|
||||
marker = ".session-tile--tier-idle .tile-body"
|
||||
assert marker in css, "idle .tile-body rule must exist"
|
||||
idx = css.index(marker)
|
||||
block_start = css.index("{", idx)
|
||||
block_end = css.index("}", block_start)
|
||||
block = css[block_start:block_end]
|
||||
assert "display: none" not in block, (
|
||||
".session-tile--tier-idle .tile-body must not use display:none "
|
||||
"(hides all tile content on mobile)"
|
||||
)
|
||||
|
||||
|
||||
def test_tile_body_pre_has_typography():
|
||||
"""Fix 2a: .tile-body pre must carry font-family and color declarations.
|
||||
|
||||
Previously those rules were on dead .tile-pre class which was never in HTML.
|
||||
"""
|
||||
css = read_css()
|
||||
marker = ".tile-body pre"
|
||||
assert marker in css, ".tile-body pre rule must exist"
|
||||
idx = css.index(marker)
|
||||
block_start = css.index("{", idx)
|
||||
block_end = css.index("}", block_start)
|
||||
block = css[block_start:block_end]
|
||||
assert "font-family" in block, ".tile-body pre must declare font-family"
|
||||
assert "color" in block, ".tile-body pre must declare color"
|
||||
|
||||
|
||||
def test_mobile_active_tier_targets_tile_body_pre_not_tile_pre():
|
||||
"""Fix 2b: mobile active-tier selector must be .tile-body pre, not .tile-pre.
|
||||
|
||||
.tile-pre is never applied in HTML; the real element is <pre> inside .tile-body.
|
||||
"""
|
||||
css = read_css()
|
||||
assert ".session-tile--tier-active .tile-body pre" in css, (
|
||||
"mobile active-tier must target .tile-body pre"
|
||||
)
|
||||
assert ".session-tile--tier-active .tile-pre" not in css, (
|
||||
".tile-pre is a dead class — selector must be removed"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user