0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-15 17:21:17 -05:00

♻️ Refactor frontend error handling.

This commit is contained in:
Andrey Antukh 2021-09-30 13:56:07 +02:00 committed by Andrés Moya
parent 7199ab7cbe
commit 77cf4a5332
5 changed files with 68 additions and 64 deletions

View file

@ -19,6 +19,7 @@
[app.main.ui.confirm]
[app.main.ui.modal :refer [modal]]
[app.main.worker]
[app.main.errors]
[app.util.dom :as dom]
[app.util.i18n :as i18n]
[app.util.router :as rt]

View file

@ -4,8 +4,8 @@
;;
;; Copyright (c) UXBOX Labs SL
(ns app.main.ui.errors
"Error handling"
(ns app.main.errors
"Generic error handling"
(:require
[app.common.exceptions :as ex]
[app.config :as cf]
@ -20,7 +20,36 @@
[expound.alpha :as expound]
[potok.core :as ptk]))
;; --- Error Handling
(defn on-error
"A general purpose error handler."
[error]
(cond
(instance? ExceptionInfo error)
(-> error sentry/capture-exception ex-data ptk/handle-error)
(map? error)
(ptk/handle-error error)
:else
(let [hint (ex-message error)
msg (str "Internal Error: " hint)]
(sentry/capture-exception error)
(ts/schedule (st/emitf (dm/assign-exception error)))
(js/console.group msg)
(ex/ignoring (js/console.error error))
(js/console.groupEnd msg))))
;; Set the main potok error handler
(reset! st/on-error on-error)
;; We receive a explicit authentication error; this explicitly clears
;; all profile data and redirect the user to the login page. This is
;; here and not in app.main.errors because of circular dependency.
(defmethod ptk/handle-error :authentication
[_]
(ts/schedule (st/emitf (du/logout))))
;; That are special case server-errors that should be treated
;; differently.
@ -33,12 +62,6 @@
(ts/schedule
(st/emitf (dm/assign-exception error))))
;; We receive a explicit authentication error; this explicitly clears
;; all profile data and redirect the user to the login page.
(defmethod ptk/handle-error :authentication
[_]
(ts/schedule (st/emitf (du/logout))))
;; Error that happens on an active bussines model validation does not
;; passes an validation (example: profile can't leave a team). From
;; the user perspective a error flash message should be visualized but
@ -52,14 +75,15 @@
:timeout 3000})))
;; Print to the console some debug info.
(js/console.group "Validation Error")
(js/console.group "Validation Error:")
(ex/ignoring
(js/console.info
(with-out-str
(pprint (dissoc error :explain))))
(when-let [explain (:explain error)]
(js/console.error explain)))
(js/console.groupEnd "Validation Error"))
(js/console.groupEnd "Validation Error:"))
;; Error on parsing an SVG
(defmethod ptk/handle-error :svg-parser
@ -76,6 +100,7 @@
(defmethod ptk/handle-error :assertion
[{:keys [data stack message hint context] :as error}]
(let [message (or message hint)
message (str "Internal Assertion Error: " message)
context (str/fmt "ns: '%s'\nname: '%s'\nfile: '%s:%s'"
(:ns context)
(:name context)
@ -85,13 +110,7 @@
(st/emitf
(dm/show {:content "Internal error: assertion."
:type :error
:timeout 3000})
(ptk/event ::ev/event
{::ev/type "exception"
::ev/name "assertion-error"
:message message
:context context
:trace stack})))
:timeout 3000})))
;; Print to the console some debugging info
(js/console.group message)
@ -109,53 +128,31 @@
[{:keys [data hint] :as error}]
(let [hint (or hint (:hint data) (:message data))
info (with-out-str (pprint (dissoc data :explain)))
expl (:explain data)]
expl (:explain data)
msg (str "Internal Server Error: " hint)]
(ts/schedule
(st/emitf
(dm/show {:content "Something wrong has happened (on backend)."
:type :error
:timeout 3000})
(ptk/event ::ev/event
{::ev/type "exception"
::ev/name "server-error"
:hint hint
:info info
:explain expl})))
:timeout 3000})))
(js/console.group "Internal Server Error:")
(js/console.error "hint:" hint)
(js/console.group msg)
(js/console.info info)
(when expl (js/console.error expl))
(js/console.groupEnd "Internal Server Error:")))
(defmethod ptk/handle-error :default
[error]
(if (instance? ExceptionInfo error)
(-> error sentry/capture-exception ex-data ptk/handle-error)
(let [stack (.-stack error)
hint (or (ex-message error)
(:hint error)
(:message error))]
(ts/schedule
(st/emitf
(dm/assign-exception error)
(ptk/event ::ev/event
{::ev/type "exception"
::ev/name "unexpected-error"
:message hint
:trace (.-stack error)})))
(js/console.group "Internal error:")
(js/console.log "hint:" hint)
(ex/ignoring
(js/console.error (clj->js error))
(js/console.error "stack:" stack))
(js/console.groupEnd "Internal error:"))))
(js/console.groupEnd msg)))
(defonce uncaught-error-handler
(letfn [(on-error [event]
(ptk/handle-error (unchecked-get event "error"))
(.preventDefault ^js event))]
(.preventDefault ^js event)
(when-let [error (unchecked-get event "error")]
(let [hint (ex-message error)
msg (str "Unhandled Internal Error: " hint)]
(sentry/capture-exception error)
(ts/schedule (st/emitf (dm/assign-exception error)))
(js/console.group msg)
(ex/ignoring (js/console.error error))
(js/console.groupEnd msg))))]
(.addEventListener js/window "error" on-error)
(fn []
(.removeEventListener js/window "error" on-error))))

View file

@ -50,9 +50,10 @@
(defn capture-exception
[err]
(when (ex/ex-info? err)
(sentry/setContext "ex-data", (clj->js (ex-data err))))
(sentry/captureException err)
(when cf/sentry-dsn
(when (ex/ex-info? err)
(sentry/setContext "ex-data", (clj->js (ex-data err))))
(sentry/captureException err))
err)

View file

@ -17,11 +17,15 @@
(enable-console-print!)
(def ^:dynamic *on-error* identity)
(defonce loader (l/atom false))
(defonce state (ptk/store {:resolve ptk/resolve}))
(defonce stream (ptk/input-stream state))
(defonce on-error (l/atom identity))
(defonce state
(ptk/store {:resolve ptk/resolve
:on-error (fn [e] (@on-error e))}))
(defonce stream
(ptk/input-stream state))
(defonce last-events
(let [buffer (atom #queue [])

View file

@ -8,14 +8,15 @@
(:require
[app.common.spec :as us]
[app.config :as cf]
[app.main.data.messages :as dm]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.auth :refer [auth]]
[app.main.ui.auth.verify-token :refer [verify-token]]
[app.main.ui.components.fullscreen :as fs]
[app.main.ui.context :as ctx]
[app.main.ui.cursors :as c]
[app.main.ui.dashboard :refer [dashboard]]
[app.main.ui.errors]
[app.main.ui.icons :as i]
[app.main.ui.messages :as msgs]
[app.main.ui.onboarding]
@ -90,7 +91,7 @@
(mf/defc on-main-error
[{:keys [error] :as props}]
(mf/use-effect #(ptk/handle-error error))
(mf/use-effect (st/emitf (dm/assign-exception error)))
[:span "Internal application errror"])
(mf/defc main-page