Reduce output of config validation errors

This commit is contained in:
shamoon
2026-06-02 20:36:38 -07:00
parent 91f3b9df5c
commit cbb5667512
4 changed files with 41 additions and 12 deletions
+21 -3
View File
@@ -2,12 +2,15 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
import createMockRes from "test-utils/create-mock-res";
const { checkAndCopyConfig } = vi.hoisted(() => ({
const { checkAndCopyConfig, getSettings } = vi.hoisted(() => ({
checkAndCopyConfig: vi.fn(),
getSettings: vi.fn(() => ({})),
}));
vi.mock("utils/config/config", () => ({
default: checkAndCopyConfig,
getSettings,
CONF_DIR: "/tmp",
}));
import handler from "pages/api/validate";
@@ -18,13 +21,28 @@ describe("pages/api/validate", () => {
});
it("returns errors for any configs that don't validate", async () => {
checkAndCopyConfig.mockReturnValueOnce(true).mockReturnValueOnce("settings bad").mockReturnValue(true);
checkAndCopyConfig
.mockReturnValueOnce(true)
.mockReturnValueOnce({
name: "YAMLException",
config: "settings.yaml",
reason: "settings bad",
mark: { line: 1 },
})
.mockReturnValue(true);
const req = {};
const res = createMockRes();
await handler(req, res);
expect(res.body).toEqual(["settings bad"]);
expect(res.body).toEqual([
{
name: "YAMLException",
config: "settings.yaml",
reason: "settings bad",
mark: { line: 1 },
},
]);
});
});
+3 -4
View File
@@ -324,13 +324,12 @@ describe("pages/index Index routing + SWR branches", () => {
});
it("renders config errors when /api/validate returns a list of errors", async () => {
state.validateData = [{ config: "services.yaml", reason: "broken", mark: { snippet: "x: y" } }];
state.validateData = [{ config: "services.yaml", name: "Service 1", reason: "broken", mark: { line: 4 } }];
await renderIndex({ initialSettings: { title: "Homepage", layout: {} }, settings: { layout: {} } });
expect(screen.getByText("services.yaml")).toBeInTheDocument();
expect(screen.getByText("broken")).toBeInTheDocument();
expect(screen.getByText("x: y")).toBeInTheDocument();
expect(screen.getByText(/services.yaml/)).toBeInTheDocument();
expect(screen.getByText(/line 4/)).toBeInTheDocument();
});
it("marks the UI stale when the hash changes and triggers a revalidate reload", async () => {
+12 -2
View File
@@ -1,9 +1,19 @@
import checkAndCopyConfig from "utils/config/config";
import createLogger from "utils/logger";
const configs = ["docker.yaml", "settings.yaml", "services.yaml", "bookmarks.yaml", "kubernetes.yaml", "proxmox.yaml"];
const logger = createLogger("configValidationHandler");
export default async function handler(req, res) {
const errors = configs.map((config) => checkAndCopyConfig(config)).filter((status) => status !== true);
let errors = configs.map((config) => checkAndCopyConfig(config)).filter((status) => status !== true);
if (errors.length > 0) {
logger.error("Configuration validation errors", errors);
errors = errors.map((error) => ({
name: error.name,
config: error.config,
reason: error.reason,
mark: { line: error.mark?.line },
}));
}
res.send(errors);
}
+5 -3
View File
@@ -167,11 +167,13 @@ function Index({ initialSettings, fallback }) {
>
<div className="bg-amber-200 text-amber-800 dark:text-amber-200 dark:bg-amber-800 p-2 rounded-md font-bold">
<BiError className="float-right w-6 h-6" />
{error.config}
{error.name} - {error.config}
</div>
<div className="p-2 text-theme-100 dark:text-theme-200">
<pre className="opacity-50 font-bold pb-2">{error.reason}</pre>
<pre className="text-sm">{error.mark.snippet}</pre>
<pre className="opacity-50 font-bold pb-2">
Reason: "{error.reason}" at line {error.mark?.line}
</pre>
<pre className="font-italic">Check logs for details.</pre>
</div>
</div>
))}