mirror of
https://github.com/penpot/penpot.git
synced 2025-05-24 06:27:20 +02:00
♻️ Refactor frontend error handling.
This commit is contained in:
parent
7199ab7cbe
commit
77cf4a5332
5 changed files with 68 additions and 64 deletions
|
@ -19,6 +19,7 @@
|
||||||
[app.main.ui.confirm]
|
[app.main.ui.confirm]
|
||||||
[app.main.ui.modal :refer [modal]]
|
[app.main.ui.modal :refer [modal]]
|
||||||
[app.main.worker]
|
[app.main.worker]
|
||||||
|
[app.main.errors]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n]
|
[app.util.i18n :as i18n]
|
||||||
[app.util.router :as rt]
|
[app.util.router :as rt]
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) UXBOX Labs SL
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
(ns app.main.ui.errors
|
(ns app.main.errors
|
||||||
"Error handling"
|
"Generic error handling"
|
||||||
(:require
|
(:require
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
|
@ -20,7 +20,36 @@
|
||||||
[expound.alpha :as expound]
|
[expound.alpha :as expound]
|
||||||
[potok.core :as ptk]))
|
[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
|
;; That are special case server-errors that should be treated
|
||||||
;; differently.
|
;; differently.
|
||||||
|
@ -33,12 +62,6 @@
|
||||||
(ts/schedule
|
(ts/schedule
|
||||||
(st/emitf (dm/assign-exception error))))
|
(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
|
;; Error that happens on an active bussines model validation does not
|
||||||
;; passes an validation (example: profile can't leave a team). From
|
;; passes an validation (example: profile can't leave a team). From
|
||||||
;; the user perspective a error flash message should be visualized but
|
;; the user perspective a error flash message should be visualized but
|
||||||
|
@ -52,14 +75,15 @@
|
||||||
:timeout 3000})))
|
:timeout 3000})))
|
||||||
|
|
||||||
;; Print to the console some debug info.
|
;; Print to the console some debug info.
|
||||||
(js/console.group "Validation Error")
|
(js/console.group "Validation Error:")
|
||||||
(ex/ignoring
|
(ex/ignoring
|
||||||
(js/console.info
|
(js/console.info
|
||||||
(with-out-str
|
(with-out-str
|
||||||
(pprint (dissoc error :explain))))
|
(pprint (dissoc error :explain))))
|
||||||
(when-let [explain (:explain error)]
|
(when-let [explain (:explain error)]
|
||||||
(js/console.error explain)))
|
(js/console.error explain)))
|
||||||
(js/console.groupEnd "Validation Error"))
|
(js/console.groupEnd "Validation Error:"))
|
||||||
|
|
||||||
|
|
||||||
;; Error on parsing an SVG
|
;; Error on parsing an SVG
|
||||||
(defmethod ptk/handle-error :svg-parser
|
(defmethod ptk/handle-error :svg-parser
|
||||||
|
@ -76,6 +100,7 @@
|
||||||
(defmethod ptk/handle-error :assertion
|
(defmethod ptk/handle-error :assertion
|
||||||
[{:keys [data stack message hint context] :as error}]
|
[{:keys [data stack message hint context] :as error}]
|
||||||
(let [message (or message hint)
|
(let [message (or message hint)
|
||||||
|
message (str "Internal Assertion Error: " message)
|
||||||
context (str/fmt "ns: '%s'\nname: '%s'\nfile: '%s:%s'"
|
context (str/fmt "ns: '%s'\nname: '%s'\nfile: '%s:%s'"
|
||||||
(:ns context)
|
(:ns context)
|
||||||
(:name context)
|
(:name context)
|
||||||
|
@ -85,13 +110,7 @@
|
||||||
(st/emitf
|
(st/emitf
|
||||||
(dm/show {:content "Internal error: assertion."
|
(dm/show {:content "Internal error: assertion."
|
||||||
:type :error
|
:type :error
|
||||||
:timeout 3000})
|
:timeout 3000})))
|
||||||
(ptk/event ::ev/event
|
|
||||||
{::ev/type "exception"
|
|
||||||
::ev/name "assertion-error"
|
|
||||||
:message message
|
|
||||||
:context context
|
|
||||||
:trace stack})))
|
|
||||||
|
|
||||||
;; Print to the console some debugging info
|
;; Print to the console some debugging info
|
||||||
(js/console.group message)
|
(js/console.group message)
|
||||||
|
@ -109,53 +128,31 @@
|
||||||
[{:keys [data hint] :as error}]
|
[{:keys [data hint] :as error}]
|
||||||
(let [hint (or hint (:hint data) (:message data))
|
(let [hint (or hint (:hint data) (:message data))
|
||||||
info (with-out-str (pprint (dissoc data :explain)))
|
info (with-out-str (pprint (dissoc data :explain)))
|
||||||
expl (:explain data)]
|
expl (:explain data)
|
||||||
|
msg (str "Internal Server Error: " hint)]
|
||||||
|
|
||||||
(ts/schedule
|
(ts/schedule
|
||||||
(st/emitf
|
(st/emitf
|
||||||
(dm/show {:content "Something wrong has happened (on backend)."
|
(dm/show {:content "Something wrong has happened (on backend)."
|
||||||
:type :error
|
:type :error
|
||||||
:timeout 3000})
|
:timeout 3000})))
|
||||||
(ptk/event ::ev/event
|
|
||||||
{::ev/type "exception"
|
|
||||||
::ev/name "server-error"
|
|
||||||
:hint hint
|
|
||||||
:info info
|
|
||||||
:explain expl})))
|
|
||||||
|
|
||||||
(js/console.group "Internal Server Error:")
|
(js/console.group msg)
|
||||||
(js/console.error "hint:" hint)
|
|
||||||
(js/console.info info)
|
(js/console.info info)
|
||||||
(when expl (js/console.error expl))
|
(when expl (js/console.error expl))
|
||||||
(js/console.groupEnd "Internal Server Error:")))
|
(js/console.groupEnd msg)))
|
||||||
|
|
||||||
(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:"))))
|
|
||||||
|
|
||||||
(defonce uncaught-error-handler
|
(defonce uncaught-error-handler
|
||||||
(letfn [(on-error [event]
|
(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)
|
(.addEventListener js/window "error" on-error)
|
||||||
(fn []
|
(fn []
|
||||||
(.removeEventListener js/window "error" on-error))))
|
(.removeEventListener js/window "error" on-error))))
|
|
@ -50,9 +50,10 @@
|
||||||
|
|
||||||
(defn capture-exception
|
(defn capture-exception
|
||||||
[err]
|
[err]
|
||||||
|
(when cf/sentry-dsn
|
||||||
(when (ex/ex-info? err)
|
(when (ex/ex-info? err)
|
||||||
(sentry/setContext "ex-data", (clj->js (ex-data err))))
|
(sentry/setContext "ex-data", (clj->js (ex-data err))))
|
||||||
(sentry/captureException err)
|
(sentry/captureException err))
|
||||||
err)
|
err)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,15 @@
|
||||||
|
|
||||||
(enable-console-print!)
|
(enable-console-print!)
|
||||||
|
|
||||||
(def ^:dynamic *on-error* identity)
|
|
||||||
|
|
||||||
(defonce loader (l/atom false))
|
(defonce loader (l/atom false))
|
||||||
(defonce state (ptk/store {:resolve ptk/resolve}))
|
(defonce on-error (l/atom identity))
|
||||||
(defonce stream (ptk/input-stream state))
|
|
||||||
|
(defonce state
|
||||||
|
(ptk/store {:resolve ptk/resolve
|
||||||
|
:on-error (fn [e] (@on-error e))}))
|
||||||
|
|
||||||
|
(defonce stream
|
||||||
|
(ptk/input-stream state))
|
||||||
|
|
||||||
(defonce last-events
|
(defonce last-events
|
||||||
(let [buffer (atom #queue [])
|
(let [buffer (atom #queue [])
|
||||||
|
|
|
@ -8,14 +8,15 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
|
[app.main.data.messages :as dm]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
|
[app.main.store :as st]
|
||||||
[app.main.ui.auth :refer [auth]]
|
[app.main.ui.auth :refer [auth]]
|
||||||
[app.main.ui.auth.verify-token :refer [verify-token]]
|
[app.main.ui.auth.verify-token :refer [verify-token]]
|
||||||
[app.main.ui.components.fullscreen :as fs]
|
[app.main.ui.components.fullscreen :as fs]
|
||||||
[app.main.ui.context :as ctx]
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.cursors :as c]
|
[app.main.ui.cursors :as c]
|
||||||
[app.main.ui.dashboard :refer [dashboard]]
|
[app.main.ui.dashboard :refer [dashboard]]
|
||||||
[app.main.ui.errors]
|
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.messages :as msgs]
|
[app.main.ui.messages :as msgs]
|
||||||
[app.main.ui.onboarding]
|
[app.main.ui.onboarding]
|
||||||
|
@ -90,7 +91,7 @@
|
||||||
|
|
||||||
(mf/defc on-main-error
|
(mf/defc on-main-error
|
||||||
[{:keys [error] :as props}]
|
[{:keys [error] :as props}]
|
||||||
(mf/use-effect #(ptk/handle-error error))
|
(mf/use-effect (st/emitf (dm/assign-exception error)))
|
||||||
[:span "Internal application errror"])
|
[:span "Internal application errror"])
|
||||||
|
|
||||||
(mf/defc main-page
|
(mf/defc main-page
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue