Point from the dashboard to Stalwart's own administration

A line under the cards says where the rest is: detailed metrics, the
delivery queue, logs and server settings are in Stalwart's own
administration. It links there when the operator sets STALWART_ADMIN_URL,
and stays plain text otherwise, because STALWART_URL is how this server
reaches Stalwart and is often an address no browser can open.

Several servers: a servers file entry may now be an object,
{"url": ..., "adminUrl": ...}, and a session routed to that server gets its
adminUrl. A routed domain without one gets no link rather than the default
server's, for the same reason routing never falls back. The URL is sent
only to a session that may administer.

The shipped example file stopped the server at startup: its "_comment"
key was read as a domain and refused as not a URL, while the test that
checks the example skipped it. Keys starting with an underscore are notes
now -- no mail domain starts with one -- and the example is also loaded
through the real parser in a test, so the two cannot disagree again.

Two new strings, in all nine catalogues.
This commit is contained in:
2026-09-15 08:16:52 -07:00
parent 0054b8a3ce
commit 4787e8bf12
21 changed files with 226 additions and 23 deletions
+9 -3
View File
@@ -74,9 +74,15 @@ test("every entry in the example mapping is a domain and an http(s) URL", () =>
assert.ok(domain, "a domain key is empty");
assert.ok(!seen.has(domain), `${domain} appears twice once normalised`);
seen.add(domain);
assert.equal(typeof value, "string", `${domain} is not a string`);
const url = new URL(value as string);
assert.ok(url.protocol === "http:" || url.protocol === "https:", `${domain} must be http or https`);
// A URL, or an object naming the server's URL and its administration's.
const entry = value && typeof value === "object" ? (value as Record<string, unknown>) : { url: value };
for (const [field, v] of Object.entries(entry)) {
assert.ok(field === "url" || field === "adminUrl", `${domain} has an unknown field ${field}`);
assert.equal(typeof v, "string", `${domain} ${field} is not a string`);
const url = new URL(v as string);
assert.ok(url.protocol === "http:" || url.protocol === "https:", `${domain} ${field} must be http or https`);
}
assert.equal(typeof entry.url, "string", `${domain} has no url`);
}
assert.ok(seen.size > 0, "the example should show at least one mapping");
});