8 Commits

Author SHA1 Message Date
wmantly c7ec65e0d9 Standardize page width, card layouts; mark SSO users external and read-only
- All pages now wrap their content in <div class="container mt-4">,
  matching sso-manager-node's width instead of rendering full-bleed inside
  the fluid shell.
- Users and Permissions pages converted from bare <table>s to the same
  card-grid convention already used on the Groups page.
- Users backed by SSO/OIDC login (backing === 'oidc', set by the redis
  user model's JIT-provisioning path) are now marked "External (SSO)" and
  their password-change control is hidden; PUT /password/:username also
  rejects with 403 server-side for such users. Deletion stays allowed.
  Redis-backend only -- LDAP/PAM deployments have no per-record marker for
  this today.
- app-base.js (byte-identical across the 3 apps): added
  app.util.revealItem(), wired into the Users/Permissions create flows.
- Bumped @simpleworkjs/frontend to ^0.2.7.
2026-07-29 22:09:50 -04:00
wmantly c0e04d1a56 Unify API-token UI: modal-based create, new Edit modal (#191)
Continues the cross-app API-token UI unification (jump-host landed first).
proxy already had the card grid and a description field, so this is a
smaller diff: converts the always-visible inline create-form card into a
"+ New Token" button + app.modal (matching the Add-Resource/Add-Host
convention used stack-wide, per explicit direction to standardize on the
modal-button approach rather than sso-manager-node's inline-card style),
adds a net-new Edit modal (proxy's PUT /api-token/:id already fully
supported it -- no route change needed), and replaces the static
#secretModal with the same bare app.modal showToken()/copyFieldValue()
pattern jump-host uses.

Found and fixed a real timing bug along the way: the create flow's
evalAJAX called app.modal.close() immediately before showToken() (which
calls app.modal.open()) in the same synchronous tick. app.modal is a
singleton, and close() immediately followed by open() collides with
Bootstrap's hide-transition guard -- show() silently no-ops while
_isTransitioning is still true from the just-started hide(), so the
"secret revealed" modal never actually appeared after creating a token.
Confirmed via a live click-through: the reveal modal stayed invisible
(title set, `.show` class never added) with the close() call, and rendered
correctly with it removed.

Also fixed the same latent bug in jump-host's already-shipped v1.10.0
(submitApiToken() had the identical close()-then-open() sequence) and in
sso-manager-node's directory.ejs (saveResource()'s OAuth-secret-reveal
path, softened there by an intervening `await loadResources()` but not
guaranteed race-free).

Verified live: create -> reveal modal now appears correctly; Edit modal
shows real created-by/on data, saves a description change, card refreshes.
2026-07-28 20:40:39 -04:00
wmantly 36c3f7a881 Remove native confirm() calls in revokeToken/rotateToken
Native confirm() blocks browser automation entirely (found live, mid
browser-test of the app.messages/app.modal adoption, on sso-manager-node's
equivalent flow). Both functions already receive btn, whose .closest('.card')
is already used for the error path, so app.messages.confirm targets the
same card.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 16:50:33 -04:00
wmantly 0a659428dd Adopt @simpleworkjs/frontend's messages/modal/validate modules
Same swap as sso-manager-node/jump-host: vendored app.util.actionMessage/
actionConfirm replaced by @simpleworkjs/frontend's app.messages.action/
confirm (real HTML-escaping, toast fallback); vendored val.js replaced by
the package's app.validate.js.

proxy's host/target/hostname validation rules (mirrored from the backend's
utils/hostname_validate.js — wildcard DNS patterns, not something other
apps need) move to public/js/app.js, registered via $.validateSettings,
since they're proxy-specific and don't belong in the shared package's
generic rule set (eq/user/password/ip).

app.api/app.auth/app.pubsub/app.socket in app-base.js are untouched, same
reasoning as sso-manager-node's PR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 14:07:14 -04:00
wmantly 426fa111ec Add plain-language concept docs; fix docs viewer rendering; link API tokens
- New docs/concepts-{hosts,dns,access,api-tokens}.md -- plain-language
  guides aimed at less technical readers, each linking onward to the
  existing system-design-level doc for anyone who wants that detail.
  Card help links (Proxy List, Add/Edit host, DNS Provider cards,
  Users/Permissions/Groups cards) now point here instead of straight at
  Installation/Architecture.
- 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.
- Fixed cross-doc links never resolving in-app, since this viewer serves
  docs at /docs/<slug> with no .html suffix: rewritten to the correct
  in-app URL, first by registered slug, falling back to the doc's real
  filename (the correct, working link form on the Jekyll/GitHub Pages
  build) -- same idea as the existing image-path fix, and lets one link
  written in a doc work on both targets.

Bumps to v1.1.13.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
2026-07-17 22:09:53 -04:00
wmantly 3f4f98ec4e Unify nav: drop Profile nav item, fold API Tokens into Profile page
- Nav bar already showed the logged-in user's name linking to /profile
  (cl-username); just removed the separate "Profile" and "API Tokens"
  nav items now that Profile covers both.
- Merge api_tokens.ejs into profile.ejs as a section below the existing
  profile card. /api-tokens 301-redirects to /profile.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 23:44:05 -04:00
wmantly 8aab9c7673 Wrap unresponsive tables in table-responsive (#131)
permissions.ejs (6 columns), users.ejs (3 columns incl. an inline
password-change form), and profile.ejs's domain-permissions table had
no .table-responsive wrapper, so on narrow/mobile viewports they'd
either overflow the page horizontally or force zoomed-out, unreadable
text instead of scrolling within the table. hosts.ejs already had the
wrapper — these three didn't.

Verified: EJS compiles, npm test 192/192 pass, and fetched each route
from a running instance to confirm the wrapper is present in the
served HTML.
2026-07-14 21:17:33 -04:00
wmantly 2acc3644c4 Permissions: rename Grants, add wildcards, local groups, profile
- Rename Grant -> Permission end-to-end (model, routes, view, frontend,
  bootstrap) and add an idempotent redis migration for existing records.
- utils/roles.js: glob domain matching (* = one label, ** = any depth) against
  the full host; authz passes the full hostname.
- Local groups: LocalGroup model + admin routes/UI; membership merged into
  Permission.effectiveFor so app groups behave like SSO groups.
- Subject autocomplete via GET /api/permission/subjects (users + derived groups).
- User profile page (/profile) and username in the navbar; /api/user/me now
  returns merged/local/external groups.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 10:54:15 -04:00