feat: add View-scoped quick access presentation
This commit is contained in:
@@ -306,12 +306,30 @@ manifest = ModuleManifest(
|
||||
"so they can always be inspected and changed. The titlebar eye "
|
||||
"opens the selector and is accented while a specialized View is "
|
||||
"active. Hidden functions remain protected by their normal "
|
||||
"permission checks."
|
||||
"permission checks. A revision may recommend Quick Access tools or "
|
||||
"focus the rail to a task-specific subset. These fields affect presentation "
|
||||
"only: unavailable, context-incompatible, or unauthorized tools stay absent, "
|
||||
"and an unusable focus falls back to the normal effective rail. Workflow uses "
|
||||
"the same behavior by resolving the exact immutable View revision."
|
||||
),
|
||||
layer="available",
|
||||
documentation_types=("admin", "user"),
|
||||
audience=("administrator", "power_user", "workflow_designer"),
|
||||
related_modules=("access", "admin", "policy", "workflow_engine"),
|
||||
translations={
|
||||
"de": {
|
||||
"title": "Aufgabenbezogene Ansichten",
|
||||
"summary": "Die sichtbare Oberflaeche auf die fuer eine Aufgabe benoetigten Module und Funktionen begrenzen, ohne Berechtigungen zu aendern.",
|
||||
"body": (
|
||||
"Ansichten sind versionierte Darstellungsprojektionen. Module melden ihre waehlbaren Oberflaechen ueber "
|
||||
"den Plattformvertrag. Eine Revision darf Schnellzugriffswerkzeuge empfehlen oder die Leiste auf eine "
|
||||
"aufgabenbezogene Teilmenge fokussieren. Das aendert nur die Darstellung: nicht verfuegbare, unpassende "
|
||||
"oder unberechtigte Werkzeuge bleiben verborgen; ein nicht nutzbarer Fokus faellt auf die normale wirksame "
|
||||
"Leiste zurueck. Workflow erhaelt dasselbe Verhalten durch die genaue unveraenderliche Ansichtsversion. "
|
||||
"Ausgeblendete Funktionen bleiben durch ihre normalen Berechtigungspruefungen geschuetzt."
|
||||
),
|
||||
}
|
||||
},
|
||||
links=(
|
||||
DocumentationLink(
|
||||
label="Views administration",
|
||||
@@ -358,7 +376,8 @@ manifest = ModuleManifest(
|
||||
"Inherited definitions or assignments must be changed in their owning scope."
|
||||
" Product-area grouping, ordering, and labels are presentation metadata in the same revision; "
|
||||
"they cannot expose a hidden surface or grant authority. Grouped navigation is the sensible default, "
|
||||
"while flat navigation preserves the complete authorized tool rail."
|
||||
"while flat navigation preserves the complete authorized tool rail. Quick Access recommendation and "
|
||||
"focus ids are likewise revisioned presentation metadata and never authorize a contribution."
|
||||
),
|
||||
documentation_types=("admin",),
|
||||
audience=("administrator", "power_user", "workflow_designer"),
|
||||
|
||||
@@ -52,8 +52,15 @@ LOCKOUT_ADMIN_SURFACE_IDS = {
|
||||
}
|
||||
_KEY_RE = re.compile(r"[^a-z0-9]+")
|
||||
_PRESENTATION_ID_RE = re.compile(r"^[a-z][a-z0-9-]{1,79}$")
|
||||
_QUICK_ACCESS_TOOL_ID_RE = re.compile(r"^[a-z][a-z0-9_-]*(?:\.[a-z0-9_-]+)+$")
|
||||
_PRESENTATION_KEYS = frozenset(
|
||||
{"navigation_mode", "product_area_order", "product_area_labels"}
|
||||
{
|
||||
"navigation_mode",
|
||||
"product_area_order",
|
||||
"product_area_labels",
|
||||
"quick_access_recommended_tool_ids",
|
||||
"quick_access_focused_tool_ids",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -419,6 +426,31 @@ def normalize_view_presentation(
|
||||
labels[area_id] = label
|
||||
normalized["product_area_labels"] = labels
|
||||
|
||||
for field_name, label in (
|
||||
("quick_access_recommended_tool_ids", "recommended Quick Access tools"),
|
||||
("quick_access_focused_tool_ids", "focused Quick Access tools"),
|
||||
):
|
||||
raw_tool_ids = value.get(field_name)
|
||||
if raw_tool_ids is None:
|
||||
continue
|
||||
if not isinstance(raw_tool_ids, list) or len(raw_tool_ids) > 100:
|
||||
raise ViewsValidationError(
|
||||
f"View {label} must be a list of at most 100 ids"
|
||||
)
|
||||
tool_ids: list[str] = []
|
||||
for raw_id in raw_tool_ids:
|
||||
tool_id = str(raw_id).strip()
|
||||
if not _QUICK_ACCESS_TOOL_ID_RE.fullmatch(tool_id):
|
||||
raise ViewsValidationError(
|
||||
f"Invalid Quick Access tool id in View presentation: {tool_id!r}"
|
||||
)
|
||||
if tool_id in tool_ids:
|
||||
raise ViewsValidationError(
|
||||
f"Duplicate Quick Access tool id in View presentation: {tool_id}"
|
||||
)
|
||||
tool_ids.append(tool_id)
|
||||
normalized[field_name] = tool_ids
|
||||
|
||||
if available_product_area_ids is not None:
|
||||
available = {str(item) for item in available_product_area_ids}
|
||||
referenced = set(normalized.get("product_area_order", ())) | set(
|
||||
|
||||
Reference in New Issue
Block a user