mirror of
https://github.com/penpot/penpot.git
synced 2025-06-04 12:41:40 +02:00
🚧 Major refactor of backend code.
Relevant changes: - ring -> vertx - suricatta -> vertx-pgsql - emails improvements - logging - hybrid sync/async -> full async execution model - database layout refactor
This commit is contained in:
parent
73753ce071
commit
e9b00339a5
134 changed files with 5394 additions and 6598 deletions
|
@ -9,7 +9,7 @@
|
|||
[beicon.core :as rx]
|
||||
[clojure.set :as set]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.repo :as rp]
|
||||
[uxbox.main.repo.core :as rp]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.util.color :as color]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
|
@ -56,9 +56,12 @@
|
|||
(defrecord FetchCollections []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :fetch/kvstore "color-collections")
|
||||
(rx/map :payload)
|
||||
(rx/map collections-fetched))))
|
||||
(->> (rp/query! :kvstore-entry {:key "color-collections"})
|
||||
(rx/map collections-fetched)
|
||||
(rx/catch (fn [{:keys [type] :as error}]
|
||||
(if (= type :not-found)
|
||||
(rx/empty)
|
||||
(rx/throw error)))))))
|
||||
|
||||
(defn fetch-collections
|
||||
[]
|
||||
|
@ -99,8 +102,7 @@
|
|||
data {:id "color-collections"
|
||||
:version version
|
||||
:value value}]
|
||||
(->> (rp/req :update/kvstore data)
|
||||
(rx/map :payload)
|
||||
(->> (rp/mutation! :upsert-kvstore data)
|
||||
(rx/map collections-fetched)))))
|
||||
|
||||
(defn persist-collections
|
||||
|
|
|
@ -5,17 +5,18 @@
|
|||
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.data.icons
|
||||
(:require [cuerdas.core :as str]
|
||||
[beicon.core :as rx]
|
||||
[uxbox.util.data :refer (jscoll->vec)]
|
||||
[uxbox.util.uuid :as uuid]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.router :as r]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.files :as files]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.repo :as rp]))
|
||||
(:require
|
||||
[beicon.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.repo.core :as rp]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.util.data :refer (jscoll->vec)]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.files :as files]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.router :as r]
|
||||
[uxbox.util.uuid :as uuid]))
|
||||
|
||||
;; --- Initialize
|
||||
|
||||
|
@ -67,8 +68,7 @@
|
|||
(defrecord FetchCollections []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :fetch/icon-collections)
|
||||
(rx/map :payload)
|
||||
(->> (rp/query! :icons-collections)
|
||||
(rx/map collections-fetched))))
|
||||
|
||||
(defn fetch-collections
|
||||
|
@ -97,9 +97,8 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [name (tr "ds.default-library-title" (gensym "c"))
|
||||
coll {:name name}]
|
||||
(->> (rp/req :create/icon-collection coll)
|
||||
(rx/map :payload)
|
||||
data {:name name}]
|
||||
(->> (rp/mutation! :create-icons-collection data)
|
||||
(rx/map collection-created)))))
|
||||
|
||||
(defn create-collection
|
||||
|
@ -126,9 +125,8 @@
|
|||
(defrecord UpdateCollection [id]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [item (get-in state [:icons-collections id])]
|
||||
(->> (rp/req :update/icon-collection item)
|
||||
(rx/map :payload)
|
||||
(let [data (get-in state [:icons-collections id])]
|
||||
(->> (rp/mutation! :update-icons-collection data)
|
||||
(rx/map collection-updated)))))
|
||||
|
||||
(defn update-collection
|
||||
|
@ -160,7 +158,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [type (get-in state [:dashboard :icons :type])]
|
||||
(->> (rp/req :delete/icon-collection id)
|
||||
(->> (rp/mutation! :delete-icons-collection {:id id})
|
||||
(rx/map #(select-collection type))))))
|
||||
|
||||
(defn delete-collection
|
||||
|
@ -219,7 +217,7 @@
|
|||
(allowed? [file]
|
||||
(= (.-type file) "image/svg+xml"))
|
||||
(prepare [[content metadata]]
|
||||
{:collection id
|
||||
{:collection-id id
|
||||
:content content
|
||||
:id (uuid/random)
|
||||
;; TODO Keep the name of the original icon
|
||||
|
@ -229,7 +227,7 @@
|
|||
(rx/filter allowed?)
|
||||
(rx/flat-map parse)
|
||||
(rx/map prepare)
|
||||
(rx/flat-map #(rp/req :create/icon %))
|
||||
(rx/flat-map #(rp/mutation! :create-icon %))
|
||||
(rx/map :payload)
|
||||
(rx/map icon-created)))))
|
||||
|
||||
|
@ -255,9 +253,8 @@
|
|||
(defrecord PersistIcon [id]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [icon (get-in state [:icons id])]
|
||||
(->> (rp/req :update/icon icon)
|
||||
(rx/map :payload)
|
||||
(let [data (get-in state [:icons id])]
|
||||
(->> (rp/mutation! :update-icon data)
|
||||
(rx/map icon-persisted)))))
|
||||
|
||||
(defn persist-icon
|
||||
|
@ -285,9 +282,8 @@
|
|||
(defrecord FetchIcons [id]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [params {:coll id}]
|
||||
(->> (rp/req :fetch/icons params)
|
||||
(rx/map :payload)
|
||||
(let [params (cond-> {} id (assoc :collection-id id))]
|
||||
(->> (rp/query! :icons-by-collection params)
|
||||
(rx/map icons-fetched)))))
|
||||
|
||||
(defn fetch-icons
|
||||
|
@ -306,7 +302,7 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :delete/icon id)
|
||||
(->> (rp/mutation! :delete-icon {:id id})
|
||||
(rx/ignore))))
|
||||
|
||||
(defn delete-icon
|
||||
|
@ -370,8 +366,8 @@
|
|||
(->> (rx/from-coll selected)
|
||||
(rx/map #(get-in state [:icons %]))
|
||||
(rx/map #(dissoc % :id))
|
||||
(rx/map #(assoc % :collection id))
|
||||
(rx/flat-map #(rp/req :create/icon %))
|
||||
(rx/map #(assoc % :collection-id id))
|
||||
(rx/flat-map #(rp/mutation :create-icon %))
|
||||
(rx/map :payload)
|
||||
(rx/map icon-created))
|
||||
(->> (rx/from-coll selected)
|
||||
|
|
|
@ -5,20 +5,21 @@
|
|||
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.data.images
|
||||
(:require [cljs.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.repo :as rp]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.router :as rt]
|
||||
[uxbox.util.data :refer (jscoll->vec)]
|
||||
[uxbox.util.uuid :as uuid]
|
||||
[uxbox.util.time :as ts]
|
||||
[uxbox.util.spec :as us]
|
||||
[uxbox.util.router :as r]
|
||||
[uxbox.util.files :as files]))
|
||||
(:require
|
||||
[cljs.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.repo.core :as rp]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.router :as rt]
|
||||
[uxbox.util.data :refer (jscoll->vec)]
|
||||
[uxbox.util.uuid :as uuid]
|
||||
[uxbox.util.time :as ts]
|
||||
[uxbox.util.spec :as us]
|
||||
[uxbox.util.router :as r]
|
||||
[uxbox.util.files :as files]))
|
||||
|
||||
;; --- Specs
|
||||
|
||||
|
@ -30,21 +31,20 @@
|
|||
(s/def ::mimetype string?)
|
||||
(s/def ::thumbnail us/url-str?)
|
||||
(s/def ::id uuid?)
|
||||
(s/def ::version integer?)
|
||||
(s/def ::url us/url-str?)
|
||||
(s/def ::collection (s/nilable uuid?))
|
||||
(s/def ::user uuid?)
|
||||
(s/def ::collection-id (s/nilable ::us/uuid))
|
||||
(s/def ::user-id ::us/uuid)
|
||||
|
||||
(s/def ::collection-entity
|
||||
(s/keys :req-un [::id
|
||||
::name
|
||||
::created-at
|
||||
::modified-at
|
||||
::user
|
||||
::version]))
|
||||
::user-id]))
|
||||
|
||||
(s/def ::image-entity
|
||||
(s/keys :req-un [::id
|
||||
(s/keys :opt-un [::collection-id]
|
||||
:req-un [::id
|
||||
::name
|
||||
::width
|
||||
::height
|
||||
|
@ -53,9 +53,7 @@
|
|||
::mimetype
|
||||
::thumbnail
|
||||
::url
|
||||
::version
|
||||
::collection
|
||||
::user]))
|
||||
::user-id]))
|
||||
|
||||
;; --- Initialize
|
||||
|
||||
|
@ -90,8 +88,7 @@
|
|||
(defrecord FetchCollections []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :fetch/image-collections)
|
||||
(rx/map :payload)
|
||||
(->> (rp/query! :images-collections)
|
||||
(rx/map collections-fetched))))
|
||||
|
||||
(defn fetch-collections
|
||||
|
@ -120,9 +117,8 @@
|
|||
(defrecord CreateCollection []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [coll {:name (tr "ds.default-library-title" (gensym "c"))
|
||||
:id (uuid/random)}]
|
||||
(->> (rp/req :create/image-collection coll)
|
||||
(let [data {:name (tr "ds.default-library-title" (gensym "c"))}]
|
||||
(->> (rp/mutation! :create-image-collection data)
|
||||
(rx/map :payload)
|
||||
(rx/map collection-created)))))
|
||||
|
||||
|
@ -152,8 +148,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [item (get-in state [:images-collections id])]
|
||||
(->> (rp/req :update/image-collection item)
|
||||
(rx/map :payload)
|
||||
(->> (rp/mutation! :update-images-collection item)
|
||||
(rx/map collection-updated)))))
|
||||
|
||||
(defn update-collection
|
||||
|
@ -185,7 +180,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [type (get-in state [:dashboard :images :type])]
|
||||
(->> (rp/req :delete/image-collection id)
|
||||
(->> (rp/mutation! :delete-images-collection {:id id})
|
||||
(rx/map #(rt/nav :dashboard/images nil {:type type}))))))
|
||||
|
||||
(defn delete-collection
|
||||
|
@ -223,17 +218,18 @@
|
|||
(finalize-upload [state]
|
||||
(assoc-in state [:dashboard :images :uploading] false))
|
||||
(prepare [[file [width height]]]
|
||||
{:collection id
|
||||
:mimetype (.-type file)
|
||||
:id (uuid/random)
|
||||
:file file
|
||||
:width width
|
||||
:height height})]
|
||||
(cond-> {:name (.-name file)
|
||||
:mimetype (.-type file)
|
||||
:id (uuid/random)
|
||||
:file file
|
||||
:width width
|
||||
:height height}
|
||||
id (assoc :collection-id id)))]
|
||||
(->> (rx/from-coll files)
|
||||
(rx/filter allowed-file?)
|
||||
(rx/mapcat image-size)
|
||||
(rx/map prepare)
|
||||
(rx/mapcat #(rp/req :create/image %))
|
||||
(rx/mapcat #(rp/mutation! :create-image %))
|
||||
(rx/map :payload)
|
||||
(rx/reduce conj [])
|
||||
(rx/do #(st/emit! finalize-upload))
|
||||
|
@ -266,9 +262,8 @@
|
|||
(defrecord PersistImage [id]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [image (get-in state [:images id])]
|
||||
(->> (rp/req :update/image image)
|
||||
(rx/map :payload)
|
||||
(let [data (get-in state [:images id])]
|
||||
(->> (rp/mutation! :update-image data)
|
||||
(rx/map image-persisted)))))
|
||||
|
||||
(defn persist-image
|
||||
|
@ -295,9 +290,8 @@
|
|||
(defrecord FetchImages [id]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [params {:coll id}]
|
||||
(->> (rp/req :fetch/images params)
|
||||
(rx/map :payload)
|
||||
(let [params (cond-> {} id (assoc :collection-id id))]
|
||||
(->> (rp/query! :images-by-collection params)
|
||||
(rx/map images-fetched)))))
|
||||
|
||||
(defn fetch-images
|
||||
|
@ -316,10 +310,9 @@
|
|||
(let [existing (get-in state [:images id])]
|
||||
(if existing
|
||||
(rx/empty)
|
||||
(->> (rp/req :fetch/image {:id id})
|
||||
(rx/catch rp/client-error? #(rx/empty))
|
||||
(rx/map :payload)
|
||||
(rx/map image-fetched))))))
|
||||
(->> (rp/query! :image-by-id {:id id})
|
||||
(rx/map image-fetched)
|
||||
(rx/catch rp/client-error? #(rx/empty)))))))
|
||||
|
||||
(defn fetch-image
|
||||
"Conditionally fetch image by its id. If image
|
||||
|
@ -352,7 +345,7 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :delete/image id)
|
||||
(->> (rp/mutation! :delete-image {:id id})
|
||||
(rx/ignore))))
|
||||
|
||||
(defn delete-image
|
||||
|
@ -414,8 +407,7 @@
|
|||
(let [selected (get-in state [:dashboard :images :selected])]
|
||||
(rx/merge
|
||||
(->> (rx/from-coll selected)
|
||||
(rx/flat-map #(rp/req :copy/image {:id % :collection id}))
|
||||
(rx/map :payload)
|
||||
(rx/flat-map #(rp/mutation! :copy-image {:id % :collection-id id}))
|
||||
(rx/map image-created))
|
||||
(->> (rx/from-coll selected)
|
||||
(rx/map deselect-image))))))
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
(s/def ::name ::us/string)
|
||||
(s/def ::inst ::us/inst)
|
||||
(s/def ::type ::us/keyword)
|
||||
(s/def ::project ::us/uuid)
|
||||
(s/def ::project-id ::us/uuid)
|
||||
(s/def ::created-at ::us/inst)
|
||||
(s/def ::modified-at ::us/inst)
|
||||
(s/def ::version ::us/number)
|
||||
|
@ -51,10 +51,10 @@
|
|||
(s/def ::page-entity
|
||||
(s/keys :req-un [::id
|
||||
::name
|
||||
::project
|
||||
::project-id
|
||||
::created-at
|
||||
::modified-at
|
||||
::user
|
||||
::user-id
|
||||
::metadata
|
||||
::shapes]))
|
||||
|
||||
|
@ -70,7 +70,7 @@
|
|||
|
||||
(s/def ::server-page
|
||||
(s/keys :req-un [::id ::name
|
||||
::project
|
||||
::project-id
|
||||
::version
|
||||
::created-at
|
||||
::modified-at
|
||||
|
@ -194,7 +194,7 @@
|
|||
(declare rehash-pages)
|
||||
|
||||
(s/def ::page-created-params
|
||||
(s/keys :req-un [::id ::name ::project ::metadata]))
|
||||
(s/keys :req-un [::id ::name ::project-id ::metadata]))
|
||||
|
||||
(defn page-created
|
||||
[data]
|
||||
|
@ -215,7 +215,7 @@
|
|||
;; --- Create Page Form
|
||||
|
||||
(s/def ::form-created-page-params
|
||||
(s/keys :req-un [::name ::project ::width ::height]))
|
||||
(s/keys :req-un [::name ::project-id ::width ::height]))
|
||||
|
||||
(defn form->create-page
|
||||
[{:keys [name project width height layout] :as data}]
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
(s/def ::id uuid?)
|
||||
(s/def ::name string?)
|
||||
(s/def ::version integer?)
|
||||
(s/def ::user uuid?)
|
||||
(s/def ::user-id uuid?)
|
||||
(s/def ::created-at inst?)
|
||||
(s/def ::modified-at inst?)
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
|||
(s/keys ::req-un [::id
|
||||
::name
|
||||
::version
|
||||
::user
|
||||
::user-id
|
||||
::created-at
|
||||
::modified-at]))
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
[cljs.spec.alpha :as s]
|
||||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.repo :as rp]
|
||||
[uxbox.main.repo.core :as rp]
|
||||
[uxbox.util.i18n :as i18n :refer [tr]]
|
||||
[uxbox.util.messages :as uum]
|
||||
[uxbox.util.spec :as us]
|
||||
|
@ -59,8 +59,7 @@
|
|||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :fetch/profile)
|
||||
(rx/map :payload)
|
||||
(->> (rp/query! :profile)
|
||||
(rx/map profile-fetched)))))
|
||||
|
||||
;; --- Update Profile
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
[potok.core :as ptk]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.history :as udh]
|
||||
[uxbox.main.data.icons :as udi]
|
||||
[uxbox.main.data.pages :as udp]
|
||||
[uxbox.main.data.projects :as dp]
|
||||
|
|
|
@ -12,21 +12,20 @@
|
|||
|
||||
(defmethod request :fetch/profile
|
||||
[type _]
|
||||
(let [url (str url "/profile/me")]
|
||||
(let [url (str url "/w/query/profile")]
|
||||
(send! {:method :get :url url})))
|
||||
|
||||
(defmethod request :auth/login
|
||||
[type data]
|
||||
(let [url (str url "/auth/login")]
|
||||
(let [url (str url "/login")]
|
||||
(send! {:url url
|
||||
:method :post
|
||||
:auth false
|
||||
:body data})))
|
||||
|
||||
:method :post
|
||||
:auth false
|
||||
:body data})))
|
||||
|
||||
(defmethod request :auth/logout
|
||||
[type data]
|
||||
(let [url (str url "/auth/logout")]
|
||||
(let [url (str url "/logout")]
|
||||
(send! {:url url :method :post :auth false})))
|
||||
|
||||
(defmethod request :update/profile
|
||||
|
|
135
frontend/src/uxbox/main/repo/core.cljs
Normal file
135
frontend/src/uxbox/main/repo/core.cljs
Normal file
|
@ -0,0 +1,135 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.repo.core
|
||||
(:require
|
||||
[beicon.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[uxbox.main.repo.impl :as impl]
|
||||
[uxbox.config :refer [url]]
|
||||
[uxbox.util.http :as http]
|
||||
[uxbox.util.storage :refer [storage]]
|
||||
[uxbox.util.transit :as t])
|
||||
(:import [goog.Uri QueryData]))
|
||||
|
||||
;; --- Low Level API
|
||||
|
||||
(defn- conditional-decode
|
||||
[{:keys [body headers] :as response}]
|
||||
(let [contentype (get headers "content-type")]
|
||||
(if (str/starts-with? contentype "application/transit+json")
|
||||
(assoc response :body (t/decode body))
|
||||
response)))
|
||||
|
||||
(defn- handle-http-status
|
||||
[{:keys [body status] :as response}]
|
||||
(if (http/success? response)
|
||||
(rx/of {:status status :payload body})
|
||||
(rx/throw {:status status :payload body})))
|
||||
|
||||
(def ^:private +headers+
|
||||
{"content-type" "application/transit+json"})
|
||||
|
||||
(defn- encode-query
|
||||
[params]
|
||||
(let [data (QueryData.)]
|
||||
(.extend data (clj->js params))
|
||||
(.toString data)))
|
||||
|
||||
(defn impl-send
|
||||
[{:keys [body headers auth method query url response-type]
|
||||
:or {auth true response-type :text}}]
|
||||
(let [headers (merge {"Accept" "application/transit+json,*/*"}
|
||||
(when (map? body) +headers+)
|
||||
headers)
|
||||
request {:method method
|
||||
:url url
|
||||
:headers headers
|
||||
:query-string (when query (encode-query query))
|
||||
:body (if (map? body) (t/encode body) body)}
|
||||
options {:response-type response-type
|
||||
:credentials? true}]
|
||||
(http/send! request options)))
|
||||
|
||||
(defn send!
|
||||
[request]
|
||||
(->> (impl-send request)
|
||||
(rx/map conditional-decode)
|
||||
(rx/mapcat handle-http-status)))
|
||||
|
||||
;; --- High Level API
|
||||
|
||||
(defn- handle-response
|
||||
[response]
|
||||
;; (prn "handle-response1" response)
|
||||
(cond
|
||||
(http/success? response)
|
||||
(rx/of (:body response))
|
||||
|
||||
(http/client-error? response)
|
||||
(rx/throw (:body response))
|
||||
|
||||
:else
|
||||
(rx/throw {:type :unexpected
|
||||
:code (:error response)})))
|
||||
|
||||
(defn send-query!
|
||||
[id params]
|
||||
(let [url (str url "/w/query/" (name id))]
|
||||
(->> (impl-send {:method :get :url url :query params})
|
||||
(rx/map conditional-decode)
|
||||
(rx/mapcat handle-response))))
|
||||
|
||||
(defn send-mutation!
|
||||
[id params]
|
||||
(let [url (str url "/w/mutation/" (name id))]
|
||||
(send! {:method :post
|
||||
:url url
|
||||
:body params})))
|
||||
|
||||
(defn- dispatch
|
||||
[& args]
|
||||
(first args))
|
||||
|
||||
(defmulti query dispatch)
|
||||
(defmulti mutation dispatch)
|
||||
|
||||
(defmethod query :default
|
||||
[id params]
|
||||
(send-query! id params))
|
||||
|
||||
(defmethod mutation :default
|
||||
[id params]
|
||||
(send-mutation! id params))
|
||||
|
||||
(defn query!
|
||||
([id] (query id {}))
|
||||
([id params] (query id params)))
|
||||
|
||||
(defn mutation!
|
||||
([id] (mutation id {}))
|
||||
([id params] (mutation id params)))
|
||||
|
||||
;; --- Legacy Api
|
||||
|
||||
(defn req
|
||||
"Perform a side effectfull action accesing
|
||||
remote resources."
|
||||
([type]
|
||||
(impl/request type nil))
|
||||
([type data]
|
||||
(impl/request type data)))
|
||||
|
||||
(def client-error? http/client-error?)
|
||||
(def server-error? http/server-error?)
|
||||
|
||||
(defmethod mutation :create-image
|
||||
[id params]
|
||||
(let [form (js/FormData.)]
|
||||
(run! (fn [[key val]]
|
||||
(.append form (name key) val))
|
||||
(seq params))
|
||||
(send-mutation! id form)))
|
|
@ -8,24 +8,19 @@
|
|||
"A main interface for access to remote resources."
|
||||
(:require
|
||||
[uxbox.config :refer [url]]
|
||||
[uxbox.main.repo.impl :refer [request send!]]))
|
||||
|
||||
(defmethod request :fetch/pages
|
||||
[type data]
|
||||
(let [params {:url (str url "/pages")
|
||||
:method :get}]
|
||||
(send! params)))
|
||||
[uxbox.main.repo.impl :as rp :refer [request send!]]))
|
||||
|
||||
(defmethod request :fetch/pages-by-project
|
||||
[type {:keys [project] :as params}]
|
||||
(let [url (str url "/pages")
|
||||
params {:project project}]
|
||||
(let [url (str url "/w/query/pages-by-project")
|
||||
params {:project-id project}]
|
||||
(send! {:method :get :url url :query params})))
|
||||
|
||||
(defmethod request :fetch/page-history
|
||||
[type {:keys [page] :as params}]
|
||||
(let [url (str url "/pages/" page "/history")
|
||||
query (select-keys params [:max :since :pinned])
|
||||
(let [url (str url "/w/query/page-history")
|
||||
query (-> (select-keys params [:max :since :pinned])
|
||||
(assoc :id page))
|
||||
params {:method :get :url url :query query}]
|
||||
(send! params)))
|
||||
|
||||
|
@ -44,22 +39,22 @@
|
|||
|
||||
(defmethod request :update/page
|
||||
[type {:keys [id] :as body}]
|
||||
(let [params {:url (str url "/pages/" id)
|
||||
:method :put
|
||||
(let [params {:url (str url "/w/mutation/update-page")
|
||||
:method :post
|
||||
:body body}]
|
||||
(send! params)))
|
||||
|
||||
(defmethod request :update/page-metadata
|
||||
[type {:keys [id] :as body}]
|
||||
(let [params {:url (str url "/w/mutation/update-page-metadata")
|
||||
:method :post
|
||||
:body body}]
|
||||
(send! params)))
|
||||
|
||||
|
||||
(defmethod request :update/page-history
|
||||
[type {:keys [id page] :as data}]
|
||||
(let [params {:url (str url "/pages/" page "/history/" id)
|
||||
:method :put
|
||||
:body data}]
|
||||
(send! params)))
|
||||
|
||||
(defmethod request :update/page-metadata
|
||||
[type {:keys [id metadata] :as body}]
|
||||
(let [body (dissoc body :data)
|
||||
params {:url (str url "/pages/" id "/metadata")
|
||||
:method :put
|
||||
:body body}]
|
||||
(send! params)))
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
[type data]
|
||||
;; Obtain the list of projects and decode the embedded
|
||||
;; page data in order to have it usable.
|
||||
(send! {:url (str url "/projects")
|
||||
(send! {:url (str url "/w/query/projects")
|
||||
:method :get}))
|
||||
|
||||
(defmethod request :fetch/project-by-token
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[lentes.core :as l]
|
||||
[potok.core :as ptk]
|
||||
[rumext.alpha :as mf]
|
||||
[expound.alpha :as expound]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.auth :refer [logout]]
|
||||
[uxbox.main.data.projects :as dp]
|
||||
|
@ -53,31 +54,37 @@
|
|||
|
||||
(defn- on-error
|
||||
"A default error handler."
|
||||
[{:keys [status] :as error}]
|
||||
(js/console.error "Unhandled Error:"
|
||||
"\n - message:" (ex-message error)
|
||||
"\n - data:" (pr-str (ex-data error)))
|
||||
(js/console.error error)
|
||||
[{:keys [type code] :as error}]
|
||||
(reset! st/loader false)
|
||||
(cond
|
||||
;; Unauthorized or Auth timeout
|
||||
(and (:status error)
|
||||
(or (= (:status error) 403)
|
||||
(= (:status error) 419)))
|
||||
(and (map? error)
|
||||
(= :validation type)
|
||||
(= :spec-validation code))
|
||||
(do
|
||||
(println "============ SERVER RESPONSE ERROR ================")
|
||||
(println (:explain error))
|
||||
(println "============ END SERVER RESPONSE ERROR ================"))
|
||||
|
||||
;; Unauthorized or Auth timeout
|
||||
(and (map? error)
|
||||
(= :authentication type)
|
||||
(= :unauthorized code))
|
||||
(ts/schedule 0 #(st/emit! (rt/nav :auth/login)))
|
||||
|
||||
;; Conflict
|
||||
(= status 412)
|
||||
(ts/schedule 100 #(st/emit! (uum/error (tr "errors.conflict"))))
|
||||
|
||||
;; Network error
|
||||
(= (:status error) 0)
|
||||
(and (map? error)
|
||||
(= :unexpected type)
|
||||
(= :abort code))
|
||||
(ts/schedule 100 #(st/emit! (uum/error (tr "errors.network"))))
|
||||
|
||||
;; Something else
|
||||
:else
|
||||
(ts/schedule 100 #(st/emit! (uum/error (tr "errors.generic"))))))
|
||||
(do
|
||||
(js/console.error "Unhandled Error:"
|
||||
"\n - message:" (ex-message error)
|
||||
"\n - data:" (pr-str (ex-data error)))
|
||||
(js/console.error error)
|
||||
(ts/schedule 100 #(st/emit! (uum/error (tr "errors.generic")))))))
|
||||
|
||||
(set! st/*on-error* on-error)
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
[id]
|
||||
(letfn [(selector [icons]
|
||||
(->> (vals icons)
|
||||
(filter #(= id (:collection %)))
|
||||
(filter #(= id (:collection-id %)))
|
||||
(count)))]
|
||||
(-> (comp (l/key :icons)
|
||||
(l/lens selector))
|
||||
|
@ -325,7 +325,7 @@
|
|||
(-> (comp (l/key :icons)
|
||||
(l/lens (fn [icons]
|
||||
(->> (vals icons)
|
||||
(filter #(= id (:collection %)))))))
|
||||
(filter #(= id (:collection-id %)))))))
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc grid
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
[id]
|
||||
(letfn [(selector [images]
|
||||
(->> (vals images)
|
||||
(filter #(= id (:collection %)))
|
||||
(filter #(= id (:collection-id %)))
|
||||
(count)))]
|
||||
(-> (comp (l/key :images)
|
||||
(l/lens selector))
|
||||
|
@ -310,7 +310,7 @@
|
|||
(-> (comp (l/key :images)
|
||||
(l/lens (fn [images]
|
||||
(->> (vals images)
|
||||
(filter #(= id (:collection %)))))))
|
||||
(filter #(= id (:collection-id %)))))))
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc grid
|
||||
|
|
|
@ -63,8 +63,9 @@
|
|||
[canvas page]
|
||||
(st/emit! (udp/watch-page-changes (:id page))
|
||||
(udu/watch-page-changes (:id page))
|
||||
(udh/initialize (:id page))
|
||||
(udh/watch-page-changes (:id page))
|
||||
;; TODO: temporary commented
|
||||
;; (udh/initialize (:id page))
|
||||
;; (udh/watch-page-changes (:id page))
|
||||
(dw/start-shapes-watcher (:id page)))
|
||||
(let [sub (shortcuts/init)]
|
||||
#(do (st/emit! ::udp/stop-page-watcher
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
[:aside.settings-bar.settings-bar-left
|
||||
[:div.settings-bar-inside
|
||||
(when (contains? flags :sitemap)
|
||||
[:& sitemap-toolbox {:project-id (:project page)
|
||||
[:& sitemap-toolbox {:project-id (:project-id page)
|
||||
:current-page-id (:id page)
|
||||
:page page}])
|
||||
(when (contains? flags :document-history)
|
||||
|
|
|
@ -37,14 +37,14 @@
|
|||
(dom/stop-propagation event)
|
||||
(modal/show! confirm-dialog {:on-accept delete}))
|
||||
(on-drop [item monitor]
|
||||
(st/emit! (udp/rehash-pages (:project page))))
|
||||
(st/emit! (udp/rehash-pages (:project-id page))))
|
||||
(on-hover [item monitor]
|
||||
(st/emit! (udp/move-page {:project-id (:project-id item)
|
||||
:page-id (:page-id item)
|
||||
:index index})))]
|
||||
(let [[dprops ref] (use-sortable {:type "page-item"
|
||||
:data {:page-id (:id page)
|
||||
:project-id (:project page)
|
||||
:project-id (:project-id page)
|
||||
:index index}
|
||||
:on-hover on-hover
|
||||
:on-drop on-drop})]
|
||||
|
@ -52,7 +52,7 @@
|
|||
[:div.element-list-body
|
||||
{:class (classnames :selected selected?
|
||||
:dragging (:dragging? dprops))
|
||||
:on-click #(st/emit! (rt/nav :workspace/page {:project (:project page)
|
||||
:on-click #(st/emit! (rt/nav :workspace/page {:project (:project-id page)
|
||||
:page (:id page)}))
|
||||
:on-double-click #(dom/stop-propagation %)
|
||||
:draggable true}
|
||||
|
@ -92,6 +92,7 @@
|
|||
|
||||
(mf/defc sitemap-toolbox
|
||||
[{:keys [project-id current-page-id] :as props}]
|
||||
(prn "sitemap-toolbox" props)
|
||||
(let [project-iref (mf/use-memo {:deps #js [project-id]
|
||||
:fn #(-> (l/in [:projects project-id])
|
||||
(l/derive st/state))})
|
||||
|
|
|
@ -203,3 +203,15 @@
|
|||
;; (let [keys# (map #(keyword (name %)) fields)
|
||||
;; vals# fields]
|
||||
;; (apply hash-map (interleave keys# vals#))))
|
||||
|
||||
;; (defmacro some->'
|
||||
;; [x & forms]
|
||||
;; `(let [x# (p/then' ~x (fn [v#]
|
||||
;; (when (nil? v#)
|
||||
;; (throw (ex-info "internal" {::some-interrupt true})))
|
||||
;; v#))]
|
||||
;; (-> (-> x# ~@forms)
|
||||
;; (p/catch' (fn [e#]
|
||||
;; (if (::some-interrupt (ex-data e#))
|
||||
;; nil
|
||||
;; (throw e#)))))))
|
||||
|
|
|
@ -40,7 +40,9 @@
|
|||
ErrorCode.TIMEOUT :timeout
|
||||
ErrorCode.EXCEPTION :exception
|
||||
ErrorCode.HTTP_ERROR :http
|
||||
ErrorCode.ABORT :abort))
|
||||
ErrorCode.ABORT :abort
|
||||
ErrorCode.OFFLINE :offline
|
||||
nil))
|
||||
|
||||
(defn- translate-response-type
|
||||
[type]
|
||||
|
@ -72,18 +74,18 @@
|
|||
(rx/create
|
||||
(fn [sink]
|
||||
(letfn [(on-complete [event]
|
||||
(if (or (= (.getLastErrorCode xhr) ErrorCode.HTTP_ERROR)
|
||||
(.isSuccess xhr))
|
||||
(sink (rx/end
|
||||
{:status (.getStatus xhr)
|
||||
:body (.getResponse xhr)
|
||||
:headers (normalize-headers
|
||||
(.getResponseHeaders xhr))}))
|
||||
(sink (let [type (-> (.getLastErrorCode xhr)
|
||||
(translate-error-code))
|
||||
message (.getLastError xhr)]
|
||||
(ex-info message {:type type})))))]
|
||||
|
||||
(let [type (translate-error-code (.getLastErrorCode xhr))
|
||||
status (.getStatus xhr)]
|
||||
;; (prn "on-complete" type method url)
|
||||
(if (pos? status)
|
||||
(sink (rx/end
|
||||
{:status status
|
||||
:body (.getResponse xhr)
|
||||
:headers (normalize-headers (.getResponseHeaders xhr))}))
|
||||
(sink (rx/end
|
||||
{:status 0
|
||||
:error (if (= type :http) :abort type)
|
||||
::xhr xhr})))))]
|
||||
(events/listen xhr EventType.COMPLETE on-complete)
|
||||
(.send xhr uri method body headers)
|
||||
#(.abort xhr))))))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue