Retires the static #secretModal/#editModal elements in favor of the
shared app.modal singleton, matching the pattern already shipped in
directory.ejs, proxy, and jump-host this round. Converts the
always-visible create-form card into a "+ New Token" button + modal,
switches badge classes from bg-* to text-bg-*, and replaces the
checkmark-flash copy feedback (broken by FontAwesome's <i>-to-<svg>
replacement) with toast-based copyFieldValue.
Native confirm() dialogs block browser automation entirely (discovered
via a frozen tab while browser-testing the app.messages/app.modal
adoption), and native alert()/confirm() are visually inconsistent with
the rest of the UI. Replaced every call site with
app.messages.action/confirm/toast:
- directory.ejs: rotateSecret/deleteResource confirms and all inline
save/add/remove-group/edge error alerts now target #resourceModal's
actionMessage (or, for deleteResource — called from the outer table
row, not the modal — the page's own card).
- impersonate_modal.ejs, onboarding.ejs: no local .actionMessage target
exists on these pages, so their alerts became page-wide toasts.
- executive.ejs: two alerts in sendNotification's validation now use the
existing $compose target; saveTos's alert now reuses the function's
own msgEl inline-message element instead of introducing a second
mechanism.
- users.ejs, profile.ejs, proxy's profile.ejs: toggleActive's alert
(no row context available at the call site) became a toast;
revokeInvite/revokeToken/rotateToken use the row/card element already
in scope.
- app.js: removed app.user.remove and app.oauthClient.remove, which
contained native confirm() guards and had zero callers anywhere in the
app — dead code, deleted rather than converted.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the vendored app.util.actionMessage/actionConfirm/alert (the
latter added ad hoc to fix "app.util.alert is not a function") with the
published @simpleworkjs/frontend package: app.messages.action/confirm,
app.modal.open, and app.validate.js (which also replaces the identical
vendored val.js). Gains real HTML-escaping on message content and a toast
fallback when there's no inline .actionMessage target, neither of which
the vendored code had.
app.api/app.auth/app.pubsub/app.socket in app-base.js are untouched —
they're app-specific (dual-mode callback/promise API, auth-token header
injection) and not something the generic frontend package's app.js
provides, so it isn't loaded here.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- New docs/concepts-{accounts,oauth-apps,api-tokens}.md -- plain-language
guides aimed at less technical readers, each linking onward to the
existing schema/protocol-level doc for anyone who wants that detail.
Card help links (Users, Groups, OAuth cards, My groups, Members of
<uid>'s group) now point here instead of straight at the technical
docs; the LDAP-protocol-wiring cards (raw connection details for
connecting a 3rd-party app) stay pointed at the technical ldap.md,
since that's genuinely the right depth for that task.
- The "New API Token" card had no help link at all -- added, pointing to
the new API Tokens doc.
- Fixed the in-app docs viewer rendering every docs/*.md page with a
garbled heading + stray <hr> at the top: Jekyll front matter (meant
only for the GitHub Pages build) was never stripped before being
handed to the markdown renderer. Also fixed: cross-doc links
(ldap.html, index.html, etc.) never resolved in-app, since this
viewer serves docs at /docs/<slug> with no .html suffix -- rewritten
to the correct in-app URL, same idea as the existing image-path fix.
Bumps to v1.1.12.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
The single header-wide help icon (added last release) pointed at a
per-page doc guess, but a page can have several cards covering different
topics (e.g. Integrations has both OAuth and LDAP cards). Removed it and
added a small help icon directly to each card that has real corresponding
doc content, linking straight to that doc -- Invite User/Add new
user/User List/Service Accounts (users.ejs), group cards (groups.ejs),
OAuth Apps + LDAP connection cards (integrations.ejs), My groups/Members
of <uid>'s group/New API Token (profile.ejs).
Bumps to v1.1.11.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
Every account gets a personal posixGroup at creation (its primary GID
holder) but there was no way to manage its memberUid list -- add
add/remove endpoints and a profile-page UI (admin-only), reusing the
userSelect widget already built for the manager field.
Bumps to v1.1.9.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
- Edit form's Mobile Phone field was effectively required (stray validate
attribute) -- removed.
- Service account profiles always showed the literal filler name "Service
Account" -- hidden now, since it's not meaningful. Required computing
isServiceAccount in User.get(), not just listDetail().
- Fresh service accounts could look uncategorized (missing from the
Service Accounts tab, wrong isServiceAccount) for up to 5 minutes after
creation, due to a cache-staleness race in the create route -- the user
gets cached via User.get() before the route marks it as a service
account. Cleared and re-fetched after marking.
- memberOf came back as a bare string instead of a one-element array for
users in exactly one group, causing client-side permission checks to
iterate character-by-character and incorrectly deny access -- normalized
alongside the existing manager normalization.
- Added editable group membership on the profile page ("My groups"),
admin-only, using the existing per-group member endpoints.
Bumps to v1.1.8.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
Removes the LDAP bind-only service account type in favor of a single
Unix/POSIX account model, surfaced in a new Users > Service Accounts tab.
Adds a multi-valued `manager` field to every account (defaults to the
creator, editable, and grants edit rights on the accounts a person manages
without needing app_sso_admin). homeDirectory and loginShell are now
editable from the profile edit form.
Bumps to v1.1.7.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
jq-repeat 2.1.0 (release notes: https://github.com/wmantly/jq-repeat/releases/tag/v2.1.0)
brings real fixes (throttled-update race conditions, sorted-list
reverse() leaking elements, nested-scope isolation) and a few
behavior changes. Audited every usage in this repo against the
changelog before upgrading:
- push()/unshift() now return the new array length -- every call
site in this repo is a bare statement, none consume the return
value. No risk.
- __setPut/__setTake, jr-order-reverse, nested jq-repeat templates:
not used anywhere in this repo (unlike proxy's companion PR, which
needed the __setPut/__setTake fix).
Real risk found and fixed: update() is now trailing-edge throttled
(~50ms) even on the first call, not just rapid subsequent ones.
profile.ejs's editUser()/editUserSeccess() call $.scope.editProfile
.update()/renderProfile() (which itself calls update()) and
immediately slideDown() the same element -- with the old synchronous
behavior the form was already populated by then; with throttling it
could briefly show stale/empty data. Deferred both slideUp/slideDown
pairs by 60ms (past the throttle window), per the library's own
migration guidance. Verified live (real bundled image + Playwright,
logged in as admin): the edit form's fields show real data, not
empty/stale, when checked right as the slide-open completes.
It linked to fixed personal infrastructure (718it.biz, vm42.us,
git.theta42.com) with an admin's name in one label — not appropriate for
what should be a generic, publicly-releasable template. Flagged in
theta42/sso-manager-node#45, tracked as #46; resolves that issue.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replace the separate Profile/API Tokens nav items with a single link
showing the logged-in user's name, pointing at their own profile.
- Merge admin.ejs + notifications.ejs into a new dashboard.ejs page.
/admin and /notifications now 301-redirect to /dashboard.
- Fold the API Tokens page into profile.ejs as a self-service-only
section, gated on isOwnProfile so it never appears when an admin
views another user's profile via /users/:uid. /api-tokens 301s to /.
- Fix: the section must not carry class="row" — app-base.js runs a
page-wide $('div.row').fadeIn() on every page load that would reveal
it regardless of the isOwnProfile check, since it fires before this
page's own gating logic.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>