0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-22 14:39:45 -05:00

♻️ Minor refactor of persistence layer.

This commit is contained in:
Andrey Antukh 2020-06-26 09:35:25 +02:00 committed by Hirunatan
parent bc672932ad
commit db7f17abdf
13 changed files with 235 additions and 186 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE page_change
ADD COLUMN session_id uuid DEFAULT NULL;

View file

@ -55,7 +55,11 @@
{:desc "Add new HTTP session table"
:name "0010-add-http-session-table"
:fn (mg/resource "migrations/0010-add-http-session-table.sql")}]})
:fn (mg/resource "migrations/0010-add-http-session-table.sql")}
{:desc "Add session_id field to page_change table"
:name "0011-add-session-id-field-to-page-change-table"
:fn (mg/resource "migrations/0011-add-session-id-field-to-page-change-table.sql")}]})
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Entry point

View file

@ -177,23 +177,23 @@
:context {:incoming-revn (:revn params)
:stored-revn (:revn page)}))
(let [sid (:session-id params)
changes (:changes params)
changes (:changes params)
page (-> page
(update :data blob/decode)
(update :data pmg/migrate-data)
(update :data cp/process-changes changes)
(update :data blob/encode)
(update :revn inc)
(assoc :changes (blob/encode changes)
:session-id sid))
page (-> page
(update :data blob/decode)
(update :data pmg/migrate-data)
(update :data cp/process-changes changes)
(update :data blob/encode)
(update :revn inc)
(assoc :changes (blob/encode changes)))
chng (insert-page-change! conn page)
msg {:type :page-change
:profile-id (:profile-id params)
:page-id (:id page)
:session-id sid
:revn (:revn page)
:changes changes}]
chng (insert-page-change! conn page)
msg {:type :page-change
:profile-id (:profile-id params)
:page-id (:id page)
:session-id sid
:revn (:revn page)
:changes changes}]
@(redis/run! :publish {:channel (str (:file-id page))
:message (t/encode-str msg)})
@ -206,11 +206,12 @@
(retrieve-lagged-changes conn chng params)))
(defn- insert-page-change!
[conn {:keys [revn data changes] :as page}]
[conn {:keys [revn data changes session-id] :as page}]
(let [id (uuid/next)
page-id (:id page)]
(db/insert! conn :page-change
{:id id
:session-id session-id
:page-id page-id
:revn revn
:data data
@ -218,7 +219,8 @@
(def ^:private
sql:lagged-changes
"select s.id, s.changes
"select s.id, s.revn, s.page_id,
s.session_id, s.changes
from page_change as s
where s.page_id = ?
and s.revn > ?
@ -226,13 +228,8 @@
(defn- retrieve-lagged-changes
[conn snapshot params]
(let [rows (db/exec! conn [sql:lagged-changes (:id params) (:revn params)])]
{:page-id (:id params)
:revn (:revn snapshot)
:changes (into [] (comp (map decode-row)
(map :changes)
(mapcat identity))
rows)}))
(->> (db/exec! conn [sql:lagged-changes (:id params) (:revn params)])
(mapv decode-row)))
;; --- Mutation: Delete Page

View file

@ -106,6 +106,7 @@
(s/def ::integer (s/conformer integer-conformer str))
(s/def ::not-empty-string (s/and string? #(not (str/empty? %))))
(s/def ::url string?)
(s/def ::fn fn?)
#?(:clj (s/def ::path (s/conformer path-conformer str)))
;; --- Macros

View file

@ -42,10 +42,6 @@
;; --- Specs
(s/def ::shape-attrs ::cp/shape-attrs)
(s/def ::set-of-uuid
(s/every uuid? :kind set?))
(s/def ::set-of-string
(s/every string? :kind set?))
@ -186,10 +182,11 @@
(ptk/reify ::initialize-group-check
ptk/WatchEvent
(watch [_ state stream]
;; TODO: add stoper
(->> stream
(rx/filter #(satisfies? dwc/IUpdateGroup %))
(rx/map #(adjust-group-shapes (dwc/get-ids %)))))))
(let [stoper (rx/filter (ptk/type? ::finalize-page) stream)]
(->> stream
(rx/filter #(satisfies? dwc/IUpdateGroup %))
(rx/map #(adjust-group-shapes (dwc/get-ids %)))
(rx/take-until stoper))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -271,8 +268,8 @@
(let [wprop (/ (:width vport) width)
hprop (/ (:height vport) height)
left-offset (if left-sidebar? 0 (/ (* -1 15 16) zoom))]
(-> local ;; This matches $width-settings-bar
(assoc :vport size) ;; in frontend/resources/styles/main/partials/sidebar.scss
(-> local ;; This matches $width-settings-bar
(assoc :vport size) ;; in frontend/resources/styles/main/partials/sidebar.scss
(update :vbox (fn [vbox]
(-> vbox
(update :width #(/ % wprop))
@ -280,11 +277,17 @@
(assoc :left-offset left-offset)))))))))))
;; TODO: this event is mainly replaced by `:reg-objects` change, but many events
;; are still implemented in function of this so we need to maintain it until
;; all is ported to use `:reg-objects`.
;; TODO: Additioanlly: many stuff related to rotation is not ported so
;; we need to port it before completelly remove this.
(defn adjust-group-shapes
[ids]
(ptk/reify ::adjust-group-shapes
dwc/IBatchedChange
ptk/UpdateEvent
(update [_ state]
(let [page-id (:current-page-id state)
@ -570,69 +573,7 @@
(ptk/reify ::update-shape
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
object (get-in state [:workspace-data page-id :objects id])
nobject (merge object attrs)
rops (dwc/generate-operations object nobject)
uops (dwc/generate-operations nobject object)
rchg {:type :mod-obj
:operations rops
:id id}
uchg {:type :mod-obj
:operations uops
:id id}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true}))))))
(defn update-shapes-recursive
[ids attrs]
(us/verify ::shape-attrs attrs)
(letfn [(impl-update [shape]
(cond-> (merge shape attrs)
(and (= :text (:type shape))
(string? (:fill-color attrs)))
(dwtxt/impl-update-shape-attrs {:fill (:fill-color attrs)})))
(impl-get-children [objects id]
(cons id (cph/get-children id objects)))
(impl-gen-changes [objects ids]
(loop [sids (seq ids)
cids (seq (impl-get-children objects (first sids)))
rchanges []
uchanges []]
(cond
(nil? sids)
[rchanges uchanges]
(nil? cids)
(recur (next sids)
(seq (impl-get-children objects (first (next sids))))
rchanges
uchanges)
:else
(let [id (first cids)
obj1 (get objects id)
obj2 (impl-update obj1)
rops (dwc/generate-operations obj1 obj2)
uops (dwc/generate-operations obj2 obj1)
rchg {:type :mod-obj
:operations rops
:id id}
uchg {:type :mod-obj
:operations uops
:id id}]
(recur sids
(next cids)
(conj rchanges rchg)
(conj uchanges uchg))))))]
(ptk/reify ::update-shapes-recursive
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (get-in state [:workspace-page :id])
objects (get-in state [:workspace-data page-id :objects])
[rchanges uchanges] (impl-gen-changes objects (seq ids))]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))))
(rx/of (dwc/update-shapes [id] #(merge % attrs))))))
;; --- Update Selected Shapes attrs
@ -652,8 +593,13 @@
ptk/WatchEvent
(watch [_ state stream]
(let [selected (get-in state [:workspace-local :selected])
page-id (get-in state [:workspace-page :id])]
(rx/of (update-shapes-recursive selected attrs))))))
update-fn
(fn [shape]
(cond-> (merge shape attrs)
(and (= :text (:type shape))
(string? (:fill-color attrs)))
(dwtxt/impl-update-shape-attrs {:fill (:fill-color attrs)})))]
(rx/of (dwc/update-shapes-recursive selected update-fn))))))
;; --- Shape Movement (using keyboard shorcuts)
@ -762,19 +708,6 @@
dws/deselect-all)))))
;; --- Rename Shape
(defn rename-shape
[id name]
(us/verify ::us/uuid id)
(us/verify string? name)
(ptk/reify ::rename-shape
dwc/IBatchedChange
ptk/UpdateEvent
(update [_ state]
(let [page-id (:current-page-id state)]
(update-in state [:workspace-data page-id :objects id] assoc :name name)))))
;; --- Shape Vertical Ordering
(s/def ::loc #{:up :down :bottom :top})
@ -987,21 +920,19 @@
;; --- Update Dimensions
(defn update-rect-dimensions
;; Event mainly used for handling user modification of the size of the
;; object from workspace sidebar options inputs.
(defn update-dimensions
[id attr value]
(us/verify ::us/uuid id)
(us/verify #{:width :height} attr)
(us/verify ::us/number value)
(ptk/reify ::update-rect-dimensions
dwc/IBatchedChange
dwc/IUpdateGroup
(get-ids [_] [id])
(ptk/reify ::update-dimensions
ptk/WatchEvent
(watch [_ state stream]
(rx/of (dwc/update-shapes [id] #(geom/resize-rect % attr value))))))
ptk/UpdateEvent
(update [_ state]
(let [page-id (:current-page-id state)]
(update-in state [:workspace-data page-id :objects id]
geom/resize-rect attr value)))))
;; --- Shape Proportions
@ -1260,6 +1191,18 @@
pages (vec (concat before [id] after))]
(assoc-in state [:projects (:project-id page) :pages] pages)))))
(defn update-shape-flags
[id {:keys [blocked hidden] :as flags}]
(s/assert ::us/uuid id)
(s/assert ::shape-attrs flags)
(ptk/reify ::update-shape-flags
ptk/WatchEvent
(watch [_ state stream]
(letfn [(update-fn [obj]
(cond-> obj
(boolean? blocked) (assoc :blocked blocked)
(boolean? hidden) (assoc :hidden hidden)))]
(rx/of (dwc/update-shapes-recursive [id] update-fn))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GROUPS
@ -1481,6 +1424,7 @@
(def handle-selection dws/handle-selection)
(def select-inside-group dws/select-inside-group)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shortcuts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -314,3 +314,93 @@
(map (fn [id] {id true}))
(into {}))))]
(update-in state [:workspace-local :expanded] expand-fn)))))
;; --- Update Shape Attrs
;; NOTE: This is a generic implementation for update multiple shapes
;; in one single commit/undo entry.
(s/def ::coll-of-uuid
(s/every ::us/uuid))
(defn update-shapes
([ids f] (update-shapes ids f nil))
([ids f {:keys [reg-objects?] :or {reg-objects? false}}]
(us/assert ::coll-of-uuid ids)
(us/assert fn? f)
(ptk/reify ::update-shapes
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
objects (get-in state [:workspace-data page-id :objects])]
(loop [ids (seq ids)
rch []
uch []]
(if (nil? ids)
(rx/of (commit-changes
(cond-> rch reg-objects? (conj {:type :reg-objects :shapes (vec ids)}))
(cond-> uch reg-objects? (conj {:type :reg-objects :shapes (vec ids)}))
{:commit-local? true}))
(let [id (first ids)
obj1 (get objects id)
obj2 (f obj1)
rchg {:type :mod-obj
:operations (generate-operations obj1 obj2)
:id id}
uchg {:type :mod-obj
:operations (generate-operations obj2 obj1)
:id id}]
(recur (next ids)
(conj rch rchg)
(conj uch uchg))))))))))
(defn update-shapes-recursive
[ids f]
(us/assert ::coll-of-uuid ids)
(us/assert fn? f)
(letfn [(impl-get-children [objects id]
(cons id (cph/get-children id objects)))
(impl-gen-changes [objects ids]
(loop [sids (seq ids)
cids (seq (impl-get-children objects (first sids)))
rchanges []
uchanges []]
(cond
(nil? sids)
[rchanges uchanges]
(nil? cids)
(recur (next sids)
(seq (impl-get-children objects (first (next sids))))
rchanges
uchanges)
:else
(let [id (first cids)
obj1 (get objects id)
obj2 (f obj1)
rops (generate-operations obj1 obj2)
uops (generate-operations obj2 obj1)
rchg {:type :mod-obj
:operations rops
:id id}
uchg {:type :mod-obj
:operations uops
:id id}]
(recur sids
(next cids)
(conj rchanges rchg)
(conj uchanges uchg))))))]
(ptk/reify ::update-shapes-recursive
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (get-in state [:workspace-page :id])
objects (get-in state [:workspace-data page-id :objects])
[rchanges uchanges] (impl-gen-changes objects (seq ids))]
(rx/of (commit-changes rchanges uchanges {:commit-local? true})))))))

View file

@ -13,6 +13,7 @@
[cljs.spec.alpha :as s]
[potok.core :as ptk]
[uxbox.common.data :as d]
[uxbox.common.geom.point :as gpt]
[uxbox.common.pages :as cp]
[uxbox.common.spec :as us]
[uxbox.main.data.dashboard :as dd]
@ -20,8 +21,8 @@
[uxbox.main.data.workspace.common :as dwc]
[uxbox.main.repo :as rp]
[uxbox.main.store :as st]
[uxbox.common.geom.point :as gpt]
[uxbox.util.i18n :as i18n :refer [tr]]
[uxbox.util.object :as obj]
[uxbox.util.router :as rt]
[uxbox.util.time :as dt]
[uxbox.util.transit :as t]))
@ -34,32 +35,42 @@
(defn initialize-page-persistence
[page-id]
(ptk/reify ::initialize-persistence
ptk/UpdateEvent
(update [_ state]
(assoc state :current-page-id page-id))
(letfn [(enable-reload-stoper []
(obj/set! js/window "onbeforeunload" (constantly false)))
(disable-reload-stoper []
(obj/set! js/window "onbeforeunload" nil))]
(ptk/reify ::initialize-persistence
ptk/UpdateEvent
(update [_ state]
(assoc state :current-page-id page-id))
ptk/WatchEvent
(watch [_ state stream]
(let [stoper (rx/filter #(= ::finalize %) stream)
notifier (->> stream
(rx/filter (ptk/type? ::dwc/commit-changes))
(rx/debounce 200)
(rx/merge stoper))]
(rx/merge
(->> stream
(rx/filter (ptk/type? ::dwc/commit-changes))
(rx/map deref)
(rx/buffer-until notifier)
(rx/map vec)
(rx/filter (complement empty?))
(rx/map #(persist-changes page-id %))
(rx/take-until (rx/delay 100 stoper)))
(->> stream
(rx/filter #(satisfies? dwc/IBatchedChange %))
(rx/debounce 200)
(rx/map (fn [_] (dwc/diff-and-commit-changes page-id)))
(rx/take-until stoper)))))))
ptk/WatchEvent
(watch [_ state stream]
(let [stoper (rx/filter #(= ::finalize %) stream)
notifier (->> stream
(rx/filter (ptk/type? ::dwc/commit-changes))
(rx/debounce 2000)
(rx/merge stoper))]
(rx/merge
(->> stream
(rx/filter (ptk/type? ::dwc/commit-changes))
(rx/map deref)
(rx/tap enable-reload-stoper)
(rx/buffer-until notifier)
(rx/map vec)
(rx/filter (complement empty?))
(rx/map #(persist-changes page-id %))
(rx/take-until (rx/delay 100 stoper)))
(->> stream
(rx/filter (ptk/type? ::changes-persisted))
(rx/tap disable-reload-stoper)
(rx/ignore)
(rx/take-until stoper))
(->> stream
(rx/filter #(satisfies? dwc/IBatchedChange %))
(rx/debounce 10)
(rx/map (fn [_] (dwc/diff-and-commit-changes page-id)))
(rx/take-until stoper))))))))
(defn persist-changes
[page-id changes]
@ -74,6 +85,11 @@
:session-id sid
:changes changes}]
(->> (rp/mutation :update-page params)
(rx/map (fn [lagged]
(if (= #{sid} (into #{} (map :session-id) lagged))
(map #(assoc % :changes []) lagged)
lagged)))
(rx/mapcat seq)
(rx/map shapes-changes-persisted))))))
(s/def ::shapes-changes-persisted
@ -85,10 +101,9 @@
(ptk/reify ::changes-persisted
ptk/UpdateEvent
(update [_ state]
(let [session-id (:session-id state)
state (-> state
(assoc-in [:workspace-pages page-id :revn] revn))
changes (filter #(not= session-id (:session-id %)) changes)]
(let [sid (:session-id state)
page (get-in state [:workspace-pages page-id])
state (update-in state [:workspace-pages page-id :revn] #(max % revn))]
(-> state
(update-in [:workspace-data page-id] cp/process-changes changes)
(update-in [:workspace-pages page-id :data] cp/process-changes changes))))))

View file

@ -9,15 +9,16 @@
(ns uxbox.main.data.workspace.texts
(:require
[clojure.walk :as walk]
["slate" :as slate :refer [Editor Node Transforms Text]]
["slate-react" :as rslate]
[beicon.core :as rx]
[cljs.spec.alpha :as s]
[clojure.walk :as walk]
[goog.object :as gobj]
[potok.core :as ptk]
[uxbox.util.object :as obj]
[uxbox.main.fonts :as fonts]
[uxbox.main.data.workspace.common :as dwc]
["slate-react" :as rslate]
["slate" :as slate :refer [Editor Node Transforms Text]]))
[uxbox.main.fonts :as fonts]
[uxbox.util.object :as obj]))
(defn create-editor
[]
@ -171,13 +172,9 @@
(editor-set! editor (clj->js attrs) #js {:match pred :split split})))
(ptk/reify ::update-attrs
dwc/IBatchedChange
ptk/UpdateEvent
(update [_ state]
(let [page-id (get-in state [:workspace-page :id])
merge-attrs #(merge-attrs % attrs)]
(update-in state [:workspace-data page-id :objects id]
#(impl-update-shape-attrs % attrs pred)))))))
ptk/WatchEvent
(watch [_ state stream]
(rx/of (dwc/update-shapes [id] #(impl-update-shape-attrs % attrs pred)))))))
(defn update-text-attrs
[options]

View file

@ -368,16 +368,15 @@
:displacement displacement}))
;; Set-rotation is custom because applies different modifiers to each shape adjusting their position
;; Set-rotation is custom because applies different modifiers to each
;; shape adjusting their position.
(defn set-rotation
([delta-rotation shapes]
(set-rotation delta-rotation shapes (-> shapes gsh/selection-rect gsh/center)))
([delta-rotation shapes center]
(ptk/reify ::set-rotation
dwc/IUpdateGroup
(get-ids [_] (map :id shapes))
ptk/UpdateEvent
(update [_ state]
(let [page-id (:current-page-id state)]

View file

@ -54,10 +54,10 @@
do-bring-to-front #(st/emit! (dw/vertical-order-selected :top))
do-send-backward #(st/emit! (dw/vertical-order-selected :down))
do-send-to-back #(st/emit! (dw/vertical-order-selected :bottom))
do-show-shape #(st/emit! (dw/update-shapes-recursive [id] {:hidden false}))
do-hide-shape #(st/emit! (dw/update-shapes-recursive [id] {:hidden true}))
do-lock-shape #(st/emit! (dw/update-shapes-recursive [id] {:blocked true}))
do-unlock-shape #(st/emit! (dw/update-shapes-recursive [id] {:blocked false}))
do-show-shape #(st/emit! (dw/update-shape-flags id {:hidden false}))
do-hide-shape #(st/emit! (dw/update-shape-flags id {:hidden true}))
do-lock-shape #(st/emit! (dw/update-shape-flags id {:blocked true}))
do-unlock-shape #(st/emit! (dw/update-shape-flags id {:blocked false}))
do-create-group #(st/emit! dw/group-selected)
do-remove-group #(st/emit! dw/ungroup-selected)]
[:*

View file

@ -59,7 +59,7 @@
parent (.-parentNode parent)
name (dom/get-value target)]
(set! (.-draggable parent) true)
(st/emit! (dw/rename-shape (:id shape) name))
(st/emit! (dw/update-shape (:id shape) {:name name}))
(swap! local assoc :edition false)))
on-key-down (fn [event]
(when (kbd/enter? event)
@ -118,15 +118,15 @@
(fn [event]
(dom/stop-propagation event)
(if (:blocked item)
(st/emit! (dw/update-shapes-recursive [id] {:blocked false}))
(st/emit! (dw/update-shapes-recursive [id] {:blocked true}))))
(st/emit! (dw/update-shape-flags id {:blocked false}))
(st/emit! (dw/update-shape-flags id {:blocked true}))))
toggle-visibility
(fn [event]
(dom/stop-propagation event)
(if (:hidden item)
(st/emit! (dw/update-shapes-recursive [id] {:hidden false}))
(st/emit! (dw/update-shapes-recursive [id] {:hidden true}))))
(st/emit! (dw/update-shape-flags id {:hidden false}))
(st/emit! (dw/update-shape-flags id {:hidden true}))))
select-shape
(fn [event]

View file

@ -33,8 +33,8 @@
on-preset-selected
(fn [width height]
(st/emit! (udw/update-rect-dimensions (:id shape) :width width)
(udw/update-rect-dimensions (:id shape) :height height)))
(st/emit! (udw/update-dimensions (:id shape) :width width)
(udw/update-dimensions (:id shape) :height height)))
on-orientation-clicked
(fn [orientation]
@ -42,15 +42,15 @@
height (:height shape)
new-width (if (= orientation :horiz) (max width height) (min width height))
new-height (if (= orientation :horiz) (min width height) (max width height))]
(st/emit! (udw/update-rect-dimensions (:id shape) :width new-width)
(udw/update-rect-dimensions (:id shape) :height new-height))))
(st/emit! (udw/update-dimensions (:id shape) :width new-width)
(udw/update-dimensions (:id shape) :height new-height))))
on-size-change
(fn [event attr]
(let [value (-> (dom/get-target event)
(dom/get-value)
(d/parse-integer 0))]
(st/emit! (udw/update-rect-dimensions (:id shape) attr value))))
(st/emit! (udw/update-dimensions (:id shape) attr value))))
on-proportion-lock-change
(fn [event]

View file

@ -36,7 +36,7 @@
(let [value (-> (dom/get-target event)
(dom/get-value)
(d/parse-integer 0))]
(st/emit! (udw/update-rect-dimensions (:id shape) attr value))))
(st/emit! (udw/update-dimensions (:id shape) attr value))))
on-proportion-lock-change
(fn [event]