The hero, the picker and the create-user card showed the active project while
the app bar still read "Select a project". Three separate causes, all of them
the same shape - a reader with its own copy of the value.
1. Nothing told the bar. wp-chrome.js rendered projectLabel() once at build
time and refreshed it only when /api/projects came back, so selecting a
project updated the hero and left the bar behind. ProjectData.setActive now
notifies, and the bar subscribes through ProjectData.onActiveChange instead
of holding a copy. A plain array of callbacks - this is one value with a
handful of readers, not a reason for a state library.
2. admin.html and users.html load wp-chrome.js but never loaded
project-data.js, so window.ProjectData was undefined and their bar could
NEVER show a project - it read "Select a project" permanently, whatever was
selected. Both now load it, ahead of wp-chrome.js.
3. setActive({id}) erased the name. field.js, wp-creation-app.js and
work-package-suite-app.js all set the id first and the full record second;
writing that stub verbatim left the bar rendering "(unnamed)". setActive now
merges onto the stored record when the id matches, so a partial write cannot
lose fields it did not mean to touch.
Also: index.html never honoured ?project=<id>, though every other page does, so
a deep link on a browser with nothing stored showed "Select a project" while
the URL said otherwise. It now resolves the parameter before reconciling.
setActive is the only code path that writes wp_active_project /
wp_active_project_obj - project-data.js:83-105, noted there in a comment so it
stays that way. A storage listener keeps a second tab from showing a project
the user has since switched away from.
Verified, all at 1440px and against the wave 0 baseline:
- bar shows the project on launcher, SOP wizard, admin, field, users
- survives a hard refresh on each of them
- selecting a project updates hero and bar in one interaction, no reload
- with nothing selected the bar reads "Select a project" and both the
launcher picker and the bar's own switcher are reachable
- deep link ?project= works on a cold browser, hero and bar agree
- setActive({id}) after a full record keeps the name
The creator is the one page with no app bar to fix: it loads neither
wp-chrome.js nor wp-chrome.css, because it renders as the iframe child of the
SOP wizard. Giving it chrome is T7.1's work once B7 dissolves that boundary -
adding it here would put a second app bar inside the embedded view. This is the
"all 6 pages" wording in the plan meeting the 7 pages that exist; see file-map
D1.
tests/f_items.py F1 now reports FIXED. F2-F6 still reproduce, untouched.
browser_check.py 71/71.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
111 lines
4.8 KiB
HTML
111 lines
4.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>User Directory — Work Package Suite</title>
|
|
<script src="auth-guard.js"></script>
|
|
<!-- Date/number formatting. Must parse BEFORE the app scripts: they format
|
|
timestamps during their own boot. -->
|
|
<script src="wp-format.js"></script>
|
|
<link rel="icon" href="favicon.ico" sizes="any">
|
|
<link rel="manifest" href="manifest.webmanifest">
|
|
<meta name="theme-color" content="#161616">
|
|
<link rel="stylesheet" href="theme-light.css">
|
|
<link rel="stylesheet" href="wp-chrome.css">
|
|
<link rel="stylesheet" href="console.css">
|
|
<link rel="stylesheet" href="wp-sidenav.css">
|
|
<style>
|
|
/* Page-specific only — everything structural is in console.css.
|
|
|
|
The directory is one wide table, so the column exceptions live here: email is
|
|
the one cell long enough to stretch a row, and the two role dropdowns need
|
|
room for "Assistant Project Manager" without pushing Actions off screen. */
|
|
#users-table table td:nth-child(3){ max-width:230px; overflow:hidden; text-overflow:ellipsis; }
|
|
#users-banner:not(:empty), #scope-banner:not(:empty){ margin-bottom:var(--s3); }
|
|
/* The create form is a lot of fields; give the password one room to breathe and
|
|
let the project picker take a full row of its own. */
|
|
#nu-password{ flex:1 1 200px; }
|
|
#nu-projects{ margin-top:var(--s2); }
|
|
#nu-projects .pickrow{ padding:var(--s1) var(--s1); }
|
|
/* A manager with one project doesn't need a scrolling picker; a manager with
|
|
thirty does, and it must not push the Create button below the fold. */
|
|
#nu-project-list{ max-height:200px; overflow:auto; border:1px solid var(--border); }
|
|
.whoami-chip{ font-size:12px; color:var(--muted); }
|
|
.whoami-chip strong{ color:var(--text); }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<!-- SHARED DARK APP BAR -->
|
|
<header class="wp-appbar">
|
|
<a href="index.html" class="wp-appbar-brand" title="Back to site">
|
|
<span class="wp-logo-chip"><img src="prime-controls-logo.jpg" alt="Prime Controls"></span>
|
|
<span class="wp-appbar-title">Work Package Suite <span class="wp-appbar-sub">| User Directory</span></span>
|
|
</a>
|
|
</header>
|
|
|
|
<div class="wrap" id="users-main" style="display:none">
|
|
<div class="row" style="justify-content:space-between; margin-bottom:var(--s5)">
|
|
<div>
|
|
<h1>User Directory</h1>
|
|
<div class="sub" style="margin:0" id="dir-sub">The people on your projects — who they are, and how to reach them.</div>
|
|
</div>
|
|
<div class="row"><a class="home" href="index.html">← Site</a></div>
|
|
</div>
|
|
|
|
<!-- WHAT YOU MAY DO HERE (rendered from GET /api/auth/user-scope) -->
|
|
<div id="scope-banner"></div>
|
|
|
|
<!-- THE DIRECTORY -->
|
|
<div class="card">
|
|
<h2>People</h2>
|
|
<div class="sub" id="people-sub"></div>
|
|
<div class="toolbar">
|
|
<button onclick="loadUsers()">Refresh</button>
|
|
<input id="user-search" placeholder="Search name / username / email / job function…" oninput="renderUsers()">
|
|
<select id="user-filter" onchange="renderUsers()">
|
|
<option value="">Everyone</option>
|
|
<option value="active">Active only</option>
|
|
<option value="disabled">Disabled only</option>
|
|
<option value="mine">Accounts I manage</option>
|
|
</select>
|
|
</div>
|
|
<div id="users-banner"></div>
|
|
<div id="users-table"><div class="note">Loading…</div></div>
|
|
</div>
|
|
|
|
<!-- ADD A USER (managers only; hidden otherwise) -->
|
|
<div class="card" id="create-card" style="display:none">
|
|
<h2>Add a user</h2>
|
|
<div class="sub" id="create-sub"></div>
|
|
<div class="urow">
|
|
<input id="nu-username" placeholder="Username *" autocomplete="off">
|
|
<input id="nu-fullname" placeholder="Full name" autocomplete="off">
|
|
<input id="nu-email" placeholder="Email" autocomplete="off">
|
|
<select id="nu-role" title="Permissions — what this account may do"></select>
|
|
<select id="nu-project-role" title="Job function on the project"></select>
|
|
<input id="nu-password" type="password" placeholder="Password (min 12)" autocomplete="new-password">
|
|
</div>
|
|
<div id="nu-projects">
|
|
<div class="note" id="nu-projects-label" style="margin-bottom:var(--s1)"></div>
|
|
<div id="nu-project-list"></div>
|
|
</div>
|
|
<div class="row" style="margin-top:var(--s3)">
|
|
<button class="primary" onclick="createUser()">Create user</button>
|
|
<span id="users-create-msg" class="note" style="margin:0"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="console-util.js"></script>
|
|
<script src="users.js"></script>
|
|
<!-- The app bar's project switcher reads ProjectData; without this the bar on this
|
|
page could never show a project and always read "Select a project" (F1). Must
|
|
parse before wp-chrome.js, which reads it as it mounts. -->
|
|
<script src="project-data.js"></script>
|
|
<script src="wp-chrome.js"></script>
|
|
<script src="wp-sidenav.js"></script>
|
|
</body>
|
|
</html>
|