Simplify error handling on events that communicate with backend.

This commit is contained in:
Andrey Antukh 2016-04-13 20:09:23 +03:00
parent 47a70ad5c9
commit 6d2cd7da59
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95
9 changed files with 63 additions and 121 deletions

View file

@ -51,14 +51,15 @@
rs/WatchEvent
(-apply-watch [this state s]
(letfn [(on-error [err]
(uum/error (tr "errors.auth"))
(letfn [(on-error [{:keys [status payload]}]
(println status payload)
(uum/error (tr "errors.auth.unauthorized"))
(rx/empty))]
(let [params {:username username
:password password
:scope "webapp"}]
(->> (rp/req :fetch/token params)
(rx/catch on-error)
(rx/catch rp/client-error? on-error)
(rx/map :payload)
(rx/mapcat #(rx/of (logged-in %)
(dp/fetch-projects)

View file

@ -40,14 +40,10 @@
rs/WatchEvent
(-apply-watch [_ state s]
(letfn [(on-success [{history :payload}]
(->PinnedPageHistoryFetched (into [] history)))
(on-failure [e]
(uum/error (tr "errors.fetch-page-history"))
(rx/empty))]
(->PinnedPageHistoryFetched (into [] history)))]
(let [params {:page id :pinned true}]
(->> (rp/req :fetch/page-history params)
(rx/map on-success)
(rx/catch on-failure))))))
(rx/map on-success))))))
(defn fetch-pinned-page-history
[id]
@ -82,16 +78,12 @@
(-apply-watch [this state s]
(letfn [(on-success [{history :payload}]
(let [history (into [] history)]
(->PageHistoryFetched history (not (nil? since)))))
(on-failure [e]
(uum/error (tr "errors.fetch-page-history"))
(rx/empty))]
(->PageHistoryFetched history (not (nil? since)))))]
(let [params (merge
{:page id :max (or max 15)}
(when since {:since since}))]
(->> (rp/req :fetch/page-history params)
(rx/map on-success)
(rx/catch on-failure))))))
(rx/map on-success))))))
(defn fetch-page-history
([id]
@ -219,14 +211,10 @@
rs/WatchEvent
(-apply-watch [_ state s]
(letfn [(on-success [{item :payload}]
(->HistoryItemUpdated item))
(on-failure [e]
(uum/error (tr "errors.page-history-update"))
(rx/empty))]
(->HistoryItemUpdated item))]
(rx/merge
(->> (rp/req :update/page-history item)
(rx/map on-success)
(rx/catch on-failure))
(rx/map on-success))
(->> (rx/filter history-updated? s)
(rx/take 1)
(rx/map #(refres-page-history (:page item))))))))

View file

@ -43,14 +43,8 @@
(defrecord FetchPages [projectid]
rs/WatchEvent
(-apply-watch [_ state s]
(letfn [(on-loaded [{pages :payload}]
(->PagesFetched pages))
(on-error [err]
(js/console.error err)
(rx/empty))]
(->> (rp/req :fetch/pages-by-project {:project projectid})
(rx/map on-loaded)
(rx/catch on-error)))))
(->> (rp/req :fetch/pages-by-project {:project projectid})
(rx/map (comp ->PagesFetched :payload)))))
(defn fetch-pages
[projectid]
@ -64,15 +58,11 @@
(letfn [(on-created [{page :payload}]
(rx/of
#(stpr/unpack-page % page)
#(stpr/assoc-page % page)))
(on-failed [page]
(uum/error (tr "errors.auth"))
(rx/empty))]
#(stpr/assoc-page % page)))]
(let [params (-> (into {} this)
(assoc :data {}))]
(->> (rp/req :create/page params)
(rx/mapcat on-created)
(rx/catch on-failed))))))
(rx/mapcat on-created))))))
(def ^:private create-page-schema
{:name [sc/required sc/string]
@ -102,15 +92,9 @@
(defrecord SyncPage [id]
rs/WatchEvent
(-apply-watch [this state s]
(letfn [(on-success [{page :payload}]
(->PageSynced page))
(on-failure [e]
(uum/error (tr "errors.page-update"))
(rx/empty))]
(let [page (stpr/pack-page state id)]
(->> (rp/req :update/page page)
(rx/map on-success)
(rx/catch on-failure))))))
(let [page (stpr/pack-page state id)]
(->> (rp/req :update/page page)
(rx/map (comp ->PageSynced :payload))))))
(defn sync-page
[id]
@ -163,13 +147,9 @@
rs/WatchEvent
(-apply-watch [this state s]
(letfn [(on-success [{page :payload}]
#(assoc-in % [:pages-by-id id :version] (:version page)))
(on-failure [e]
(uum/error (tr "errors.page-update"))
(rx/empty))]
#(assoc-in % [:pages-by-id id :version] (:version page)))]
(->> (rp/req :update/page-metadata (into {} this))
(rx/map on-success)
(rx/catch on-failure)))))
(rx/map on-success)))))
(def ^:private update-page-schema
{:id [sc/required]
@ -192,15 +172,11 @@
rs/WatchEvent
(-apply-watch [_ state s]
(letfn [(on-success [_]
(rs/swap #(stpr/purge-page % id)))
(on-failure [e]
(uum/error (tr "errors.delete-page"))
(rx/empty))]
(rs/swap #(stpr/purge-page % id)))]
(->> (rp/req :delete/page id)
(rx/map on-success)
(rx/tap callback)
(rx/filter identity)
(rx/catch on-failure)))))
(rx/filter identity)))))
(defn delete-page
([id] (DeletePage. id (constantly nil)))

View file

@ -17,31 +17,6 @@
[uxbox.data.pages :as udp]
[uxbox.ui.messages :as uum]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn sort-projects-by
[ordering projs]
(case ordering
:name (sort-by :name projs)
:created (reverse (sort-by :created-at projs))
projs))
(defn contains-term?
[phrase term]
(str/contains? (str/lower phrase) (str/trim (str/lower term))))
(defn filter-projects-by
[term projs]
(if (str/blank? term)
projs
(filter #(contains-term? (:name %) term) projs)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Events
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Projects Fetched
(defrecord ProjectsFetched [projects]
@ -59,12 +34,9 @@
rs/WatchEvent
(-apply-watch [_ state s]
(letfn [(on-loaded [{projects :payload}]
#(reduce stpr/assoc-project % projects))
(on-error [err]
(rx/empty))]
#(reduce stpr/assoc-project % projects))]
(->> (rp/req :fetch/projects)
(rx/map on-loaded)
(rx/catch on-error)))))
(rx/map on-loaded)))))
(defn fetch-projects
[]
@ -94,12 +66,8 @@
:layout layout
:project (:id project)
:name "Page 1"
:data nil})))
(on-failure [err]
(uum/error (tr "errors.create-project"))
(rx/empty))]
:data nil})))]
(->> (rp/req :create/project {:name name})
(rx/catch on-failure)
(rx/mapcat on-success)))))
(def ^:private create-project-schema
@ -119,12 +87,9 @@
rs/WatchEvent
(-apply-watch [_ state s]
(letfn [(on-success [_]
(rs/swap #(stpr/dissoc-project % id)))
(on-failure [e]
(uum/error (tr "errors.delete-project")))]
(rs/swap #(stpr/dissoc-project % id)))]
(->> (rp/req :delete/project id)
(rx/map on-success)
(rx/catch on-failure)))))
(rx/map on-success)))))
(defn delete-project
[id]
@ -161,3 +126,23 @@
first page of the project."
([projectid] (GoTo. projectid))
([projectid pageid] (GoToPage. projectid pageid)))
;; --- Helpers
(defn sort-projects-by
[ordering projs]
(case ordering
:name (sort-by :name projs)
:created (reverse (sort-by :created-at projs))
projs))
(defn contains-term?
[phrase term]
(str/contains? (str/lower phrase) (str/trim (str/lower term))))
(defn filter-projects-by
[term projs]
(if (str/blank? term)
projs
(filter #(contains-term? (:name %) term) projs)))

View file

@ -53,6 +53,7 @@
"errors.form.color" "Should be a valid color string"
"errors.form.password-not-match" "Password does not match"
"errors.auth" "Username or passwords seems to be wrong."
"errors.generic" "Something work has happened."
"errors.auth.unauthorized" "Username or passwords seems to be wrong."
"errors.profile.update-password" "Error updating password, probably your old password is wrong."
})

View file

@ -7,17 +7,21 @@
(ns uxbox.repo
"A main interface for access to remote resources."
(:refer-clojure :exclude [do])
(:require [uxbox.repo.core :refer (request)]
(:require [uxbox.repo.core :as core]
[uxbox.repo.auth]
[uxbox.repo.users]
[uxbox.repo.projects]
[uxbox.repo.pages]
[httpurr.status :as status]
[beicon.core :as rx]))
(defn req
"Perform a side effectfull action accesing
remote resources."
([type]
(request type nil))
(core/request type nil))
([type data]
(request type data)))
(core/request type data)))
(def client-error? status/client-error?)
(def server-error? status/server-error?)

View file

@ -28,25 +28,11 @@
(assoc response :body (t/decode body))
response))
(defrecord Ok [status payload])
(defrecord ServerError [status paylpad])
(defrecord ClientError [status payload])
(defrecord NotFound [payload])
(defn- handle-http-status
[{:keys [body status] :as response}]
(cond
(http.status/success? response)
(rx/of (->Ok status body))
(http.status/client-error? response)
(rx/throw
(if (= status 404)
(->NotFound body)
(->ClientError status body)))
(http.status/server-error? response)
(rx/throw (->ServerError status body))))
(if (http.status/success? response)
(rx/of {:status status :payload body})
(rx/throw {:status status :payload body})))
(def ^:private ^:const +headers+
{"content-type" "application/transit+json"})

View file

@ -7,7 +7,9 @@
(ns uxbox.rstore
"Reactive storage management architecture helpers."
(:require [beicon.core :as rx]))
(:require [beicon.core :as rx]
[uxbox.locales :refer (tr)]
[uxbox.ui.messages :as uum]))
;; An abstraction for implement a simple state
;; transition. The `-apply-update` function receives
@ -89,8 +91,9 @@
(defn- on-error
"A default error handler."
[e]
(uum/error (tr "errors.generic"))
(println "Unexpected error: " e)
(js/console.error e.stack)
(js/console.log (.-stack e))
(rx/throw e))
(defn init

View file

@ -1,9 +1,7 @@
(ns uxbox.ui.messages
(:require [sablono.core :as html :refer-macros [html]]
[rum.core :as rum]
[promesa.core :as p]
[cuerdas.core :as str]
[uxbox.rstore :as rs]
[uxbox.ui.icons :as i]
[uxbox.ui.mixins :as mx]
[uxbox.util.data :refer (classnames)]