Share the excluded-ranges filter with IP Addresses; add Admin Links page
IP Addresses (IPAM) now reads the same excluded-ranges setting the Consistency page manages, so "not interesting" addresses - a Docker bridge network repeating on every host, say - can be hidden there too. Adds a "Hide excluded addresses" toggle (on by default, with a live count), an inline ranges editor matching Consistency's, an "excluded" badge on rows shown anyway, and a per-row "Exclude..." shortcut that suggests a /24 (or /64 for IPv6) around that address. Editing ranges from either page updates both, since it's one shared setting. Also adds Operations > Admin Links: a single page summarizing every admin bookmark added across all servers (Dockge, Webmin, Cockpit, etc, previously only visible per-server on each server's own detail page), sortable and searchable, with the same add/edit/delete capability - adding one here just asks which server it belongs to. Verified both with real HTTP-level tests: a genuine Express app, a scratch SQLite DB, and forged sessions, covering the exclusion matching, the shared-setting round trip, the links aggregation and join, and role enforcement - the real dev DB was confirmed untouched throughout. Both packages build clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
236b1da0dc
commit
1ff1c6550c
9 files changed
+435
-9
No files matched your search
@@ -11,6 +11,8 @@ import { loadIntegrationConfig } from "../integrations/loadIntegration.js";
|
||||
import { createTailscaleAdapter } from "../integrations/tailscale/adapter.js";
|
||||
import { createProxmoxAdapter } from "../integrations/proxmox/adapter.js";
|
||||
import { createPhpIpamAdapter } from "../integrations/phpipam/adapter.js";
|
||||
import { makeExclusion } from "../services/consistency.js";
|
||||
import { getSettings } from "../services/settingsStore.js";
|
||||
|
||||
export const ipamRouter = Router();
|
||||
|
||||
@@ -36,7 +38,14 @@ async function matchingDnsRecordsByIp(ips: string[]): Promise<Map<string, string
|
||||
ipamRouter.get("/", asyncHandler(async (_req, res) => {
|
||||
const rows = await db.select().from(ipamEntries).orderBy(ipamEntries.ipAddress);
|
||||
const byIp = await matchingDnsRecordsByIp(rows.map((r) => r.ipAddress));
|
||||
res.json({ entries: rows.map((r) => ({ ...r, matchingDnsRecords: byIp.get(r.ipAddress) ?? [] })) });
|
||||
// Same excluded-ranges setting the Consistency page manages — "not interesting" addresses (Docker's bridge
|
||||
// network repeating on every host, say) can be hidden here too, without duplicating that configuration.
|
||||
const { consistency } = await getSettings();
|
||||
const excluded = makeExclusion(consistency.excludedRanges);
|
||||
res.json({
|
||||
entries: rows.map((r) => ({ ...r, matchingDnsRecords: byIp.get(r.ipAddress) ?? [], excluded: excluded(r.ipAddress) })),
|
||||
excludedRanges: consistency.excludedRanges,
|
||||
});
|
||||
}));
|
||||
|
||||
const createInput = z.object({
|
||||
|
||||
@@ -170,6 +170,24 @@ serversRouter.get("/summary", asyncHandler(async (_req, res) => {
|
||||
res.json(buildServerSummary(rows, healthChecks, Date.now(), await activeSubjects()));
|
||||
}));
|
||||
|
||||
// For the Operations > Admin Links page — every server's admin bookmarks in one place, instead of visiting
|
||||
// each server's own detail page to find them.
|
||||
serversRouter.get("/links", asyncHandler(async (_req, res) => {
|
||||
const rows = await db
|
||||
.select({
|
||||
id: serverLinks.id,
|
||||
serverId: serverLinks.serverId,
|
||||
serverName: servers.name,
|
||||
serverHostname: servers.hostname,
|
||||
label: serverLinks.label,
|
||||
url: serverLinks.url,
|
||||
})
|
||||
.from(serverLinks)
|
||||
.innerJoin(servers, eq(serverLinks.serverId, servers.id))
|
||||
.orderBy(servers.name, serverLinks.label);
|
||||
res.json({ links: rows });
|
||||
}));
|
||||
|
||||
serversRouter.get("/:id/detail", asyncHandler(async (req, res) => {
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id)) return res.status(400).json({ error: "invalid_id" });
|
||||
|
||||
Reference in new issue
Block a user