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);
|
Printf.eprintf "[http] route error for %s: %s\n%!" path (Printexc.to_string e);
|
||||||
Nil
|
Nil
|
||||||
in
|
in
|
||||||
match route_result with
|
(* Build an error page AST that keeps the layout intact *)
|
||||||
| Nil -> None
|
let error_page_ast msg =
|
||||||
| Dict d ->
|
List [Symbol "div"; Keyword "class"; String "p-8 max-w-2xl mx-auto";
|
||||||
let is_ajax = match Hashtbl.find_opt d "is-ajax" with Some (Bool true) -> true | _ -> false in
|
List [Symbol "h2"; Keyword "class"; String "text-xl font-semibold text-rose-600 mb-4";
|
||||||
let nav_path = match Hashtbl.find_opt d "nav-path" with Some (String s) -> s | _ -> path in
|
String "Page Error"];
|
||||||
let page_ast = match Hashtbl.find_opt d "page-ast" with Some v -> v | _ -> Nil in
|
List [Symbol "p"; Keyword "class"; String "text-stone-600 mb-2"; String path];
|
||||||
if page_ast = Nil then None
|
List [Symbol "pre"; Keyword "class"; String "text-sm bg-stone-100 p-4 rounded overflow-x-auto text-stone-700";
|
||||||
else begin
|
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
|
let wrapped = List [Symbol "~layouts/doc"; Keyword "path"; String nav_path; page_ast] in
|
||||||
if is_ajax then begin
|
if is_ajax then begin
|
||||||
(* AJAX: return SX wire format (aser output) with text/sx content type *)
|
(* 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
|
Some html
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
| _ ->
|
|
||||||
Printf.eprintf "[http] unexpected handler result for %s\n%!" path;
|
|
||||||
None
|
|
||||||
|
|
||||||
(* ====================================================================== *)
|
(* ====================================================================== *)
|
||||||
(* Static file serving + file hashing *)
|
(* Static file serving + file hashing *)
|
||||||
@@ -2409,10 +2424,13 @@ let http_mode port =
|
|||||||
| Some body ->
|
| Some body ->
|
||||||
let resp = http_response ~content_type:"text/sx; charset=utf-8" body in
|
let resp = http_response ~content_type:"text/sx; charset=utf-8" body in
|
||||||
Hashtbl.replace response_cache cache_key resp; resp
|
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 ->
|
with e ->
|
||||||
Printf.eprintf "[ajax] Error for %s: %s\n%!" path (Printexc.to_string 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
|
in
|
||||||
write_response fd response; true
|
write_response fd response; true
|
||||||
end else begin
|
end else begin
|
||||||
|
|||||||
Reference in New Issue
Block a user