Files
Rpa_Skills/rpa-dashboard-no-ai/templates/sections.md
T
VasanthandClaude Opus 5.5 9a5b95448d Optional sections: checkpoint tracker, admin/roles, login page
- dashboard.html: each section sits in OPTIONAL:<name> BEGIN/END blocks in
  the style, markup and script, with sample answers so a page with no bot
  shows it working. Core change: setUser records the role on <body>, so CSS
  hides admin-only parts from operators.
- templates/sections.py keeps the chosen sections and deletes the rest,
  markers included; it stops on a broken marker.
- templates/sections.md: what each section needs from the host (events,
  actions, desktop slot snippets, the role re-check, the login hand-off).
- SKILL.md step 5 asks one multi-select question and runs sections.py.
- Page check: checkpoint states, admin visibility by role and assign/remove,
  login theme and hand-off to auth or the stub. Cases skip on a generated
  page without the section; the template must carry all three. The harness
  signs in when the page has a login screen.
- tests/test_sections.py: no sections leave no trace, and that page still
  passes the page check.
- Eval runner: a-empty-sections variant (all three) and per-section checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:31:25 +05:30

4.6 KiB

Optional sections

Three extras live in dashboard.html as marked blocks (OPTIONAL:<name> BEGIN ... END) in the style, the markup and the script. Build only the ones the user picked:

python <skill>/templates/sections.py <project>/dashboard/dashboard.html checkpoints admin login

Name only the chosen sections; name none to remove all three. The script deletes every unchosen block (markup, script and style) and the marker lines of the chosen ones, and it stops if a marker is broken. Never cut the blocks by hand.

With SAMPLE_DATA = true, every section works on its own sample answers. Once the bot is wired, the host must answer the section's actions as below. Desktop hosts add the slots to the Bridge class in bridge.py. Web hosts serve POST {API_BASE}/<action-with-dashes>, like the core actions, and send the events in the /run/status events list.

Checkpoint tracker (checkpoints)

Numbered boxes on the Run tab. Each one is pending, in progress, done or stuck.

  • Fill {{CHECKPOINTS_JSON}} with the checkpoint names, in order, from the bot's real stages, for example ["Open the portal","Load the list","Process items","Finish up"]. They can be finer than STEPS.

  • Event cpstate {kind: "pending"|"active"|"done"|"stuck", cp}. cp counts from 1. active also marks the earlier boxes done and the later ones pending, so the bot can send active for each checkpoint as it starts, and stuck when one fails.

  • Desktop: add a marker table next to STEP_MARKERS in bridge.py, and send the event from _on_line, using specific substrings the bot really prints:

    CHECKPOINT_MARKERS = [("[cp 1]", "active", 1), ("[cp 1 failed]", "stuck", 1)]  # (substring, kind, cp)
    
    # in _on_line, after the step markers:
    for marker, kind, cp in CHECKPOINT_MARKERS:
        if marker in low:
            self.send_to_js("cpstate", {"kind": kind, "cp": cp})
            break
    

Admin/roles screen (admin)

An Admin tab where an admin assigns or removes admin and operator access. The Admin nav item and the screen appear only while set_user says role: "admin"; operators never see them. Hiding them is not security: the host re-checks that the signed-in user is an admin on every admin action, and refuses otherwise.

  • Event admin_data {rows: [{username, emp_id, role: "admin"|"operator"}], msg?}. msg is shown above the list, for example "Access assigned." or "Only admins can do that."

  • Actions: load_admin() when the tab opens, assign_role(who, role), remove_role(who). who is a username or employee ID. Answer each one with a fresh admin_data.

  • Desktop slots, using the project's own user store:

    @pyqtSlot()
    def load_admin(self):
        if self.role != "admin":                     # self.role: set when the user signs in
            return
        self.send_to_js("admin_data", {"rows": read_access_list()})
    
    @pyqtSlot(str, str)
    def assign_role(self, who, role):
        if self.role == "admin" and role in ("admin", "operator"):
            save_access(who, role)
        self.load_admin()
    
    @pyqtSlot(str)
    def remove_role(self, who):
        if self.role == "admin":
            delete_access(who)
        self.load_admin()
    

Login page (login)

A sign-in screen in the page's own theme, shown over the dashboard until sign-in succeeds, plus a Sign out button in the top bar. It is UI only: it hands the username and password to the project's existing auth. Don't build an auth backend.

  • Desktop action login(username, password). The host checks them and sends login_result {ok, msg?, user?: {username, emp_id, role}}. On ok the screen closes and user fills the sidebar (and the role, if the admin screen is built). Otherwise msg shows under the form.

  • Web: POST {API_BASE}/login with JSON {username, password}, answered with the same {ok, msg?, user?} body.

  • Action logout() when the user signs out. The screen comes back.

  • The page sits behind the screen, but the host must still refuse data actions until sign-in succeeds.

  • No auth in the project yet: keep a stub that lets any non-empty username in, and tell the user it is a stub. In sample mode the page has its own stub.

    @pyqtSlot(str, str)
    def login(self, username, password):
        role = check_login(username, password)       # the project's auth: a role, or None
        self.role = role or ""
        if role:
            self.send_to_js("login_result", {"ok": True, "user": {"username": username, "emp_id": "", "role": role}})
        else:
            self.send_to_js("login_result", {"ok": False, "msg": "Wrong username or password."})
    
    @pyqtSlot()
    def logout(self):
        self.role = ""