diff --git a/internal/server/api/templates/router.go b/internal/server/api/templates/router.go index c8c947e..b965523 100644 --- a/internal/server/api/templates/router.go +++ b/internal/server/api/templates/router.go @@ -123,8 +123,7 @@ func (s *webpageRouter) serveTemplate(c *gin.Context) (response.Response, error) r := c.Request ctx := r.Context() - b, err := s.templater.Execute( - strings.Trim(r.URL.Path, "/"), + args := []any{ "Request", r, // add services and data here @@ -142,24 +141,36 @@ func (s *webpageRouter) serveTemplate(c *gin.Context) (response.Response, error) middleware.GetIdentity(ctx), "Auth", newTemplateAuthenticator(r), - ) + } + + b, err := s.templater.Execute(strings.Trim(r.URL.Path, "/"), args...) if err != nil { - return s.handleTemplateError(err) + if isFileNotFoundError(err) || isInvalidWildcardValue(err) { + werr := response.NotFound(). + Wrap(ErrTemplateNotFound{ + err: err, + }). + Msg("resource not found") + + nfb, nferr := s.templater.Execute("not-found", args...) + if nferr != nil { + s.log.Error("failed to render not-found page: %v", nferr) + return nil, werr + } + + return nil, werr. + HTML(nfb) + } + + return nil, err } return response.HTML(b), nil } -func (s *webpageRouter) handleTemplateError(err error) (response.Response, error) { - if isFileNotFoundError(err) { - return nil, response.NotFound(). - Wrap(ErrTemplateNotFound{ - err: err, - }). - Msg("resource not found") - } - - return nil, err +func isInvalidWildcardValue(err error) bool { + var te *templater.ErrInvalidWildcardValue + return errors.As(err, &te) } func isFileNotFoundError(err error) bool { diff --git a/internal/server/response/error.go b/internal/server/response/error.go index 166b7e3..a4f8c12 100644 --- a/internal/server/response/error.go +++ b/internal/server/response/error.go @@ -14,6 +14,7 @@ type ( err error msg string status int + html []byte } ) @@ -77,6 +78,11 @@ func (e ErrorResponse) Wrap(err error) ErrorResponse { return e } +func (e ErrorResponse) HTML(h []byte) ErrorResponse { + e.html = h + return e +} + // error implementation func (e ErrorResponse) Error() string { @@ -130,6 +136,19 @@ func (e ErrorResponse) GetMsg() (string, bool) { return "", false } +func (e ErrorResponse) GetHTML() ([]byte, bool) { + if len(e.html) != 0 { + return e.html, true + } + + ce, ok := GetError(e.err) + if ok { + return ce.GetHTML() + } + + return nil, false +} + func GetError(err error) (e ErrorResponse, ok bool) { ok = errors.As(err, &e) return e, ok diff --git a/internal/server/response/write.go b/internal/server/response/write.go index b2490de..96df906 100644 --- a/internal/server/response/write.go +++ b/internal/server/response/write.go @@ -52,7 +52,14 @@ func Write(c *gin.Context, res Response) { } func WriteError(c *gin.Context, err error) { - c.String(GetStatusFromError(err), err.Error()) + status := GetStatusFromError(err) + if h, ok := GetHTMLFromError(err); ok { + c.Status(status) + c.Header("Content-Type", "text/html") + c.Writer.Write(h) + } else { + c.String(status, err.Error()) + } } func GetStatusFromError(err error) int { @@ -66,3 +73,12 @@ func GetStatusFromError(err error) int { return status } + +func GetHTMLFromError(err error) ([]byte, bool) { + e, ok := GetError(err) + if !ok { + return nil, false + } + + return e.GetHTML() +} diff --git a/styles/index.css b/styles/index.css index 3ba718a..ea5e4cc 100644 --- a/styles/index.css +++ b/styles/index.css @@ -9,6 +9,8 @@ "Courier New", monospace; --color-black: #000; --color-white: #fff; + --text-sm: 0.875rem; + --text-sm--line-height: calc(1.25 / 0.875); --text-lg: 1.125rem; --text-lg--line-height: calc(1.75 / 1.125); --text-xl: 1.25rem; @@ -183,9 +185,21 @@ .static { position: static; } + .m-\[1em\] { + margin: 1em; + } + .m-\[2em\] { + margin: 2em; + } + .m-\[3em\] { + margin: 3em; + } .mt-\[1em\] { margin-top: 1em; } + .mt-\[2em\] { + margin-top: 2em; + } .mt-\[3em\] { margin-top: 3em; } @@ -302,6 +316,10 @@ font-size: var(--text-lg); line-height: var(--tw-leading, var(--text-lg--line-height)); } + .text-sm { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } .text-xl { font-size: var(--text-xl); line-height: var(--tw-leading, var(--text-xl--line-height)); diff --git a/templates/pages/not-found.html.tmpl b/templates/pages/not-found.html.tmpl new file mode 100644 index 0000000..eb7bf41 --- /dev/null +++ b/templates/pages/not-found.html.tmpl @@ -0,0 +1,31 @@ +
+
+

+ Page Not Found +

+ + {{ $link := printf "/ui%s" .Request.URL }} + + + {{ $link }} + + +
+ +
+

+ Sorry, the page you were looking for could not be found. +

+
+ +

+ If you clicked a link, perhaps it was broken. +

+

+ Please try again. +

+ +

+ If the issue persists, please reach out to support. +

+