Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9eb3dfa2e6 | |||
| a40da55993 | |||
| e5df0d3370 | |||
| fcd73169e0 |
+15
-2
@@ -6,7 +6,18 @@ correspond to git tags (`vX.Y.Z`) and `nodejs/package.json`'s `version`.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.9] - 2026-07-17
|
||||
## [1.1.11] - 2026-07-17
|
||||
|
||||
### Changed
|
||||
- Moved the help (❓) link out of the global header and onto each relevant card individually (Proxy List, Add/Edit host, Add DNS Provider, Dynamic A Records, Add New User, User List, Add Permission, Permissions, Add Group) — each now deep-links straight to the doc that actually covers it, instead of one generic header icon.
|
||||
|
||||
Bumps to v1.1.11.
|
||||
|
||||
### 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.
|
||||
|
||||
Bumps to v1.1.10.
|
||||
|
||||
### Added
|
||||
- The host list now shows who created each host, and when.
|
||||
@@ -71,7 +82,9 @@ First tagged release. Establishes the `vX.Y.Z` tag convention that the in-app up
|
||||
- Standalone backup script (`ops/backup.sh`) for deployments not using theta-env's orchestrator — snapshots Redis and `./config`, with retention.
|
||||
- Admin-only in-app banner that checks GitHub releases every 24h and surfaces available updates.
|
||||
|
||||
[Unreleased]: https://github.com/theta42/proxy/compare/v1.1.9...HEAD
|
||||
[Unreleased]: https://github.com/theta42/proxy/compare/v1.1.11...HEAD
|
||||
[1.1.11]: https://github.com/theta42/proxy/compare/v1.1.10...v1.1.11
|
||||
[1.1.10]: https://github.com/theta42/proxy/compare/v1.1.9...v1.1.10
|
||||
[1.1.9]: https://github.com/theta42/proxy/compare/v1.1.8...v1.1.9
|
||||
[1.1.8]: https://github.com/theta42/proxy/compare/v1.1.7...v1.1.8
|
||||
[1.1.7]: https://github.com/theta42/proxy/compare/v1.1.6...v1.1.7
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "proxy-api",
|
||||
"version": "1.1.9",
|
||||
"version": "1.1.11",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "proxy-api",
|
||||
"version": "1.1.9",
|
||||
"version": "1.1.11",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^7.3.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "proxy-api",
|
||||
"version": "1.1.9",
|
||||
"version": "1.1.11",
|
||||
"private": true,
|
||||
"author": [
|
||||
{
|
||||
|
||||
@@ -60,6 +60,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'});
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
Add DNS Provider
|
||||
</span>
|
||||
<span class="float-end">
|
||||
<a href="/docs/installation" class="text-reset me-2" title="Help"><i class="fa-solid fa-circle-question"></i></a>
|
||||
<i class="fa-solid fa-circle-minus"></i>
|
||||
</span>
|
||||
</div>
|
||||
@@ -226,6 +227,7 @@
|
||||
<div class="card-header d-flex align-items-center">
|
||||
<span class="card-icon me-2"><i class="fa-solid fa-tower-broadcast"></i></span>
|
||||
<span class="card-title">Dynamic A Records</span>
|
||||
<a href="/docs/installation" class="text-reset ms-2" title="Help"><i class="fa-solid fa-circle-question"></i></a>
|
||||
<span class="ms-auto text-muted small">
|
||||
This server's public IP:
|
||||
<span class="badge text-bg-primary fs-6"><i class="fa-solid fa-globe me-1"></i><span id="ddns-current-ip">…</span></span>
|
||||
|
||||
@@ -11,7 +11,12 @@
|
||||
A local copy of this project's documentation, readable from the
|
||||
running app -- no internet access required.
|
||||
</p>
|
||||
<ul class="list-group">
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text"><i class="fa-solid fa-magnifying-glass"></i></span>
|
||||
<input type="search" id="docs-search-input" class="form-control" placeholder="Search the docs…" oninput="docsSearch(this.value)">
|
||||
</div>
|
||||
<div id="docs-search-results" style="display:none"></div>
|
||||
<ul id="docs-list" class="list-group">
|
||||
<% docs.forEach(function(doc){ %>
|
||||
<li class="list-group-item">
|
||||
<a href="/docs/<%= doc.slug %>"><%= doc.title %></a>
|
||||
@@ -22,5 +27,41 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var docsSearchTimer;
|
||||
function docsSearch(q){
|
||||
clearTimeout(docsSearchTimer);
|
||||
docsSearchTimer = setTimeout(function(){ docsSearchRun(q); }, 200);
|
||||
}
|
||||
function docsSearchRun(q){
|
||||
q = (q || '').trim();
|
||||
var $results = $('#docs-search-results');
|
||||
var $list = $('#docs-list');
|
||||
if(!q){
|
||||
$results.hide().empty();
|
||||
$list.show();
|
||||
return;
|
||||
}
|
||||
// Not app.api.get() -- routes/docs.js is mounted at /docs directly,
|
||||
// not under /api, unlike the rest of this app's endpoints.
|
||||
$.getJSON('/docs/search', {q: q}, function(data){
|
||||
$list.hide();
|
||||
$results.empty().show();
|
||||
var hits = (data && data.results) || [];
|
||||
if(!hits.length){
|
||||
$results.append($('<p class="text-muted"></p>').text('No results for "' + q + '".'));
|
||||
return;
|
||||
}
|
||||
var $ul = $('<ul class="list-group"></ul>');
|
||||
hits.forEach(function(hit){
|
||||
var $li = $('<li class="list-group-item"></li>');
|
||||
$('<a></a>').attr('href', '/docs/' + hit.slug).text(hit.title).appendTo($li);
|
||||
$('<div class="text-muted small"></div>').text(hit.snippet).appendTo($li);
|
||||
$ul.append($li);
|
||||
});
|
||||
$results.append($ul);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<%- include('bottom') %>
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
<div class="card-header text-center">
|
||||
<span class="card-icon float-start"><i class="fa-solid fa-users-gear"></i></span>
|
||||
<span class="card-title">Add Group</span>
|
||||
<a href="/docs/architecture" class="text-reset float-end" title="Help"><i class="fa-solid fa-circle-question"></i></a>
|
||||
</div>
|
||||
<div class="card-header actionMessage" style="display:none"></div>
|
||||
<div class="card-body">
|
||||
|
||||
@@ -394,6 +394,7 @@
|
||||
<span class="card-icon me-2"><i class="fa-solid fa-network-wired"></i></span>
|
||||
<span class="card-title fw-bold">Proxy List</span>
|
||||
<span class="ms-auto">
|
||||
<a href="/docs/installation" class="text-reset me-2" title="Help"><i class="fa-solid fa-circle-question"></i></a>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary me-2" onclick="hostClearCache(this)" title="Clear cached wildcard subdomain lookups">
|
||||
<i class="fa-solid fa-broom"></i>
|
||||
Clear cache
|
||||
@@ -527,6 +528,7 @@
|
||||
<div class="modal-content card border-0">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="hostModalTitle">Add host</h5>
|
||||
<a href="/docs/installation" class="text-reset me-2" title="Help"><i class="fa-solid fa-circle-question"></i></a>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
<i class="fa-solid fa-user-shield"></i>
|
||||
</span>
|
||||
<span class="card-title">Add Permission</span>
|
||||
<a href="/docs/architecture" class="text-reset float-end" title="Help"><i class="fa-solid fa-circle-question"></i></a>
|
||||
</div>
|
||||
|
||||
<div class="card-header actionMessage" style="display:none"></div>
|
||||
@@ -140,6 +141,7 @@
|
||||
<i class="fa-solid fa-list-check"></i>
|
||||
</span>
|
||||
<span class="card-title">Permissions</span>
|
||||
<a href="/docs/architecture" class="text-reset float-end" title="Help"><i class="fa-solid fa-circle-question"></i></a>
|
||||
</div>
|
||||
|
||||
<div class="card-header actionMessage" style="display:none"></div>
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
Add New User
|
||||
</span>
|
||||
<span class="float-end">
|
||||
<a href="/docs/architecture" class="text-reset me-2" title="Help"><i class="fa-solid fa-circle-question"></i></a>
|
||||
<i class="fa-solid fa-circle-minus"></i>
|
||||
</span>
|
||||
</div>
|
||||
@@ -107,6 +108,7 @@
|
||||
User List
|
||||
</span>
|
||||
<span class="float-end">
|
||||
<a href="/docs/architecture" class="text-reset me-2" title="Help"><i class="fa-solid fa-circle-question"></i></a>
|
||||
<i class="fa-solid fa-circle-minus"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user