"""UI pages for attribute sets: list, inspect (with what they resolve to and who reuses them), create and edit.""" from __future__ import annotations import html from pathlib import Path from . import user as USER from .attrs import fold, save_set, set_layers, used_by EXTRA_ROWS = 3 def e(s) -> str: return html.escape(str(s)) def pill(text: str) -> str: return f"{e(text)}" def _is_app_level(doc) -> bool: return Path(doc.path) == USER.user_file() def _where(app, doc) -> str: if _is_app_level(doc): return "app (you)" for r in app.roots: try: return f"{r.name}/{Path(doc.path).relative_to(r)}" except ValueError: continue return str(doc.path) def _usage(app, reg, sid: str) -> str: u = used_by(reg, sid) parts = [] parts += [f"{e(p)}" for p in u["projects"]] parts += [f"{e(t)} (template)" for t in u["templates"]] parts += [f"{e(x)} (extends it)" for x in u["sets"]] return ", ".join(parts) or "nothing yet" def sets_page(app, msg: str = "") -> bytes: from .ui import page reg = app.registry() rows = "" for sid, doc in sorted(reg.sets.items()): n = len(doc.data.get("attributes", {})) if doc.ok else 0 state = "" if doc.ok else f" invalid: {e(doc.errors[0])}" ext = ", ".join(f"{e(x)}" for x in doc.data.get("extends", [])) or "-" rows += (f"
Named, reusable, non-secret facts. Runbooks receive them as inputs, projects and templates compose them, and one set " "can extend another (later layers win, and every value keeps its source). Nothing here may be a secret.
" + (f"{e(msg)}
" if msg else "") + ("| Set | Where it lives | Extends | Attributes | Reused by |
|---|
No attribute sets yet.
") + "{pill('app' if _is_app_level(doc) else 'repository')} {e(sid)} "
f"{e(_where(app, doc))}
{e(msg)}
") if not doc.ok: out.append("This set is invalid:
Reused by: {_usage(app, reg, sid)}
") try: folded = fold(set_layers(reg, sid)) except ValueError as ex: out.append(f"{e(ex)}
") folded = {} rows = "" for name, a in folded.items(): val = "" if a["value"] is None else a["value"] rows += (f"{e(name)}Including everything it extends; the source shows which set gave each value.
" "| Attribute | Value | Requirement | Note | Source |
|---|
This is your set: it follows you across every project. Change it on " "your settings page. A repository may define its own set with the same id, which then wins.
") return page(d.get("title", sid), "".join(out)) own = d.get("attributes", {}) trs = "" from .attrs import normalize for i, (name, a) in enumerate(normalize(own).items()): req = a.get("requirement") or "" opts = "".join(f"" for o in ("", "required", "optional")) trs += (f"Other things reuse this set. Changing a value changes what their runbooks receive from now on; " "runs that already started keep the values they started with.
") out.append("