Error pages render within layout instead of bare nil/404
Route errors and missing pages now show a styled error message inside the normal layout (header, nav still work) instead of bare "nil" text or a raw "Not Found" page. AJAX errors return renderable SX error fragments instead of "nil" strings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1544,14 +1544,32 @@ let http_render_page env path headers =
|
||||
Printf.eprintf "[http] route error for %s: %s\n%!" path (Printexc.to_string e);
|
||||
Nil
|
||||
in
|
||||
match route_result with
|
||||
| Nil -> None
|
||||
| Dict d ->
|
||||
let is_ajax = match Hashtbl.find_opt d "is-ajax" with Some (Bool true) -> true | _ -> false in
|
||||
let nav_path = match Hashtbl.find_opt d "nav-path" with Some (String s) -> s | _ -> path in
|
||||
let page_ast = match Hashtbl.find_opt d "page-ast" with Some v -> v | _ -> Nil in
|
||||
if page_ast = Nil then None
|
||||
else begin
|
||||
(* Build an error page AST that keeps the layout intact *)
|
||||
let error_page_ast msg =
|
||||
List [Symbol "div"; Keyword "class"; String "p-8 max-w-2xl mx-auto";
|
||||
List [Symbol "h2"; Keyword "class"; String "text-xl font-semibold text-rose-600 mb-4";
|
||||
String "Page Error"];
|
||||
List [Symbol "p"; Keyword "class"; String "text-stone-600 mb-2"; String path];
|
||||
List [Symbol "pre"; Keyword "class"; String "text-sm bg-stone-100 p-4 rounded overflow-x-auto text-stone-700";
|
||||
String msg]]
|
||||
in
|
||||
(* Normalize route result — Nil and non-Dict become error pages *)
|
||||
let is_ajax_req = List.exists (fun (k,_) -> String.lowercase_ascii k = "sx-request") headers in
|
||||
let route_dict = match route_result with
|
||||
| Dict d -> d
|
||||
| _ ->
|
||||
let d = Hashtbl.create 4 in
|
||||
Hashtbl.replace d "is-ajax" (Bool is_ajax_req);
|
||||
Hashtbl.replace d "nav-path" (String path);
|
||||
Hashtbl.replace d "page-ast" (error_page_ast "Page not found");
|
||||
d
|
||||
in
|
||||
let d = route_dict in
|
||||
let is_ajax = match Hashtbl.find_opt d "is-ajax" with Some (Bool true) -> true | _ -> false in
|
||||
let nav_path = match Hashtbl.find_opt d "nav-path" with Some (String s) -> s | _ -> path in
|
||||
let page_ast = match Hashtbl.find_opt d "page-ast" with Some v -> v | _ -> Nil in
|
||||
let page_ast = if page_ast = Nil then error_page_ast "Page returned empty content" else page_ast in
|
||||
begin
|
||||
let wrapped = List [Symbol "~layouts/doc"; Keyword "path"; String nav_path; page_ast] in
|
||||
if is_ajax then begin
|
||||
(* AJAX: return SX wire format (aser output) with text/sx content type *)
|
||||
@@ -1618,9 +1636,6 @@ let http_render_page env path headers =
|
||||
Some html
|
||||
end
|
||||
end
|
||||
| _ ->
|
||||
Printf.eprintf "[http] unexpected handler result for %s\n%!" path;
|
||||
None
|
||||
|
||||
(* ====================================================================== *)
|
||||
(* Static file serving + file hashing *)
|
||||
@@ -2409,10 +2424,13 @@ let http_mode port =
|
||||
| Some body ->
|
||||
let resp = http_response ~content_type:"text/sx; charset=utf-8" body in
|
||||
Hashtbl.replace response_cache cache_key resp; resp
|
||||
| None -> http_response ~status:404 "nil"
|
||||
| None -> http_response ~status:404
|
||||
"(div :class \"p-8\" (h2 :class \"text-rose-600 font-semibold\" \"Page not found\") (p :class \"text-stone-500\" \"No route matched this path\"))"
|
||||
with e ->
|
||||
Printf.eprintf "[ajax] Error for %s: %s\n%!" path (Printexc.to_string e);
|
||||
http_response ~status:500 "nil"
|
||||
http_response ~status:500
|
||||
(Printf.sprintf "(div :class \"p-8\" (h2 :class \"text-rose-600 font-semibold\" \"Render Error\") (pre :class \"text-sm bg-stone-100 p-4 rounded\" \"%s\"))"
|
||||
(escape_sx_string (Printexc.to_string e)))
|
||||
in
|
||||
write_response fd response; true
|
||||
end else begin
|
||||
|
||||
Reference in New Issue
Block a user