From 077c41844ddd9a97a701933bf465e8e3a3a02292 Mon Sep 17 00:00:00 2001 From: William Mantly Date: Fri, 17 Jul 2026 19:22:27 -0400 Subject: [PATCH] Add header help icon and in-app docs search - A ? icon in the top-right header deep-links to the doc most relevant to the current page (client-side path mapping, same pattern already used for top-nav active-link highlighting -- no server-side "current section" local exists to key off of instead). Falls back to the docs index. - GET /docs/search does a plain line-substring search over the existing allowlisted doc set. No new dependency, stays usable with no internet access. Bumps to v1.1.10. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C --- CHANGELOG.md | 9 +++++++- nodejs/package-lock.json | 4 ++-- nodejs/package.json | 2 +- nodejs/routes/docs.js | 24 +++++++++++++++++++++ nodejs/views/docs_index.ejs | 43 ++++++++++++++++++++++++++++++++++++- nodejs/views/top.ejs | 22 +++++++++++++++++++ 6 files changed, 99 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c32a170..a2933b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ correspond to git tags (`vX.Y.Z`) and `nodejs/package.json`'s `version`. ## [Unreleased] +## [1.1.10] - 2026-07-17 + +### Added +- A help icon (❓) in the top-right header now deep-links to the doc most relevant to the current page (falls back to the docs index elsewhere). +- The in-app docs viewer (`/docs`) is now searchable — a simple line-substring search over the same local doc set, no new dependency, still works with no internet access. + ## [1.1.9] - 2026-07-17 ### Added @@ -77,7 +83,8 @@ First tagged release. Establishes the `vX.Y.Z` tag convention that the in-app up - Unix/POSIX and LDAP bind-only service account support, distinct from real-person accounts. - Merged OAuth Apps + LDAP Info into a single Integrations page. -[Unreleased]: https://github.com/theta42/sso-manager-node/compare/v1.1.9...HEAD +[Unreleased]: https://github.com/theta42/sso-manager-node/compare/v1.1.10...HEAD +[1.1.10]: https://github.com/theta42/sso-manager-node/compare/v1.1.9...v1.1.10 [1.1.9]: https://github.com/theta42/sso-manager-node/compare/v1.1.8...v1.1.9 [1.1.8]: https://github.com/theta42/sso-manager-node/compare/v1.1.7...v1.1.8 [1.1.7]: https://github.com/theta42/sso-manager-node/compare/v1.1.6...v1.1.7 diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index a2bc4a2..bf7b15e 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,12 +1,12 @@ { "name": "t42-sso-manager", - "version": "1.1.9", + "version": "1.1.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "t42-sso-manager", - "version": "1.1.9", + "version": "1.1.10", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-free": "^7.3.0", diff --git a/nodejs/package.json b/nodejs/package.json index 8af4bc7..3e3798e 100755 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -1,6 +1,6 @@ { "name": "t42-sso-manager", - "version": "1.1.9", + "version": "1.1.10", "private": true, "author": [ { diff --git a/nodejs/routes/docs.js b/nodejs/routes/docs.js index 2c67733..5e36439 100644 --- a/nodejs/routes/docs.js +++ b/nodejs/routes/docs.js @@ -52,6 +52,30 @@ router.get('/', function(req, res) { res.render('docs_index', {...values, docs: docList}); }); +// Plain, dependency-free line-substring search over the same allowlisted +// doc set -- no separate index to build/maintain, no new dependency, and it +// keeps working with no internet access (same reasoning as the rest of this +// route). Must be registered before the /:slug catch-all below, or "search" +// would be treated as a (nonexistent) doc slug and 404. +router.get('/search', function(req, res) { + const q = (req.query.q || '').trim(); + if (!q) return res.json({results: []}); + const qLower = q.toLowerCase(); + + const results = []; + for (const [slug, doc] of Object.entries(DOCS)) { + try { + const content = fs.readFileSync(doc.file, 'utf8'); + const matchLine = content.split('\n').find(line => line.toLowerCase().includes(qLower)); + if (matchLine) { + results.push({slug, title: doc.title, snippet: matchLine.trim().slice(0, 200)}); + } + } catch (error) { /* unreadable doc file -- skip it */ } + } + + res.json({results}); +}); + router.get('/:slug', function(req, res, next) { const doc = DOCS[req.params.slug]; if (!doc) return next({status: 404, message: 'Doc not found'}); diff --git a/nodejs/views/docs_index.ejs b/nodejs/views/docs_index.ejs index 43c28d3..92bd78e 100644 --- a/nodejs/views/docs_index.ejs +++ b/nodejs/views/docs_index.ejs @@ -10,7 +10,12 @@ A local copy of this project's documentation, readable from the running app -- no internet access required.

-