mirror of
https://github.com/penpot/penpot.git
synced 2025-05-04 08:25:54 +02:00
208 lines
7.3 KiB
Clojure
208 lines
7.3 KiB
Clojure
;; 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) KALEIDOS INC
|
|
|
|
(ns app.main.data.changes
|
|
(:require
|
|
[app.common.data :as d]
|
|
[app.common.data.macros :as dm]
|
|
[app.common.files.changes :as cpc]
|
|
[app.common.logging :as log]
|
|
[app.common.types.shape-tree :as ctst]
|
|
[app.common.uuid :as uuid]
|
|
[app.main.features :as features]
|
|
[app.main.worker :as uw]
|
|
[app.util.time :as dt]
|
|
[beicon.v2.core :as rx]
|
|
[potok.v2.core :as ptk]))
|
|
|
|
;; Change this to :info :debug or :trace to debug this module
|
|
(log/set-level! :info)
|
|
|
|
(def page-change?
|
|
#{:add-page :mod-page :del-page :mov-page})
|
|
(def update-layout-attr?
|
|
#{:hidden})
|
|
|
|
(def commit?
|
|
(ptk/type? ::commit))
|
|
|
|
(defn- fix-page-id
|
|
"For events that modifies the page, page-id does not comes
|
|
as a property so we assign it from the `id` property."
|
|
[{:keys [id type page] :as change}]
|
|
(cond-> change
|
|
(and (page-change? type)
|
|
(nil? (:page-id change)))
|
|
(assoc :page-id (or id (:id page)))))
|
|
|
|
(defn- update-indexes
|
|
"Given a commit, send the changes to the worker for updating the
|
|
indexes."
|
|
[commit attr]
|
|
(ptk/reify ::update-indexes
|
|
ptk/WatchEvent
|
|
(watch [_ _ _]
|
|
(let [changes (->> (get commit attr)
|
|
(map fix-page-id)
|
|
(filter :page-id)
|
|
(group-by :page-id))]
|
|
|
|
(->> (rx/from changes)
|
|
(rx/merge-map (fn [[page-id changes]]
|
|
(log/debug :hint "update-indexes" :page-id page-id :changes (count changes))
|
|
(uw/ask! {:cmd :update-page-index
|
|
:page-id page-id
|
|
:changes changes})))
|
|
(rx/catch (fn [cause]
|
|
(log/warn :hint "unable to update index"
|
|
:cause cause)
|
|
(rx/empty)))
|
|
(rx/ignore))))))
|
|
|
|
(defn- get-pending-commits
|
|
[{:keys [persistence]}]
|
|
(->> (:queue persistence)
|
|
(map (d/getf (:index persistence)))
|
|
(not-empty)))
|
|
|
|
(def ^:private xf:map-page-id
|
|
(map :page-id))
|
|
|
|
(defn- apply-changes-localy
|
|
[{:keys [file-id redo-changes] :as commit} pending]
|
|
(ptk/reify ::apply-changes-localy
|
|
ptk/UpdateEvent
|
|
(update [_ state]
|
|
(let [current-file-id (get state :current-file-id)
|
|
path (if (= file-id current-file-id)
|
|
[:workspace-data]
|
|
[:libraries file-id :data])
|
|
|
|
undo-changes (if pending
|
|
(->> pending
|
|
(map :undo-changes)
|
|
(reverse)
|
|
(mapcat identity)
|
|
(vec))
|
|
nil)
|
|
|
|
redo-changes (if pending
|
|
(into redo-changes
|
|
(mapcat :redo-changes)
|
|
pending)
|
|
redo-changes)]
|
|
|
|
(d/update-in-when state path
|
|
(fn [file]
|
|
(let [file (cpc/process-changes file undo-changes false)
|
|
file (cpc/process-changes file redo-changes false)
|
|
pids (into #{} xf:map-page-id redo-changes)]
|
|
(reduce #(ctst/update-object-indices %1 %2) file pids))))))))
|
|
|
|
|
|
(defn commit
|
|
"Create a commit event instance"
|
|
[{:keys [commit-id redo-changes undo-changes origin save-undo? features
|
|
file-id file-revn file-vern undo-group tags stack-undo? source]}]
|
|
|
|
(dm/assert!
|
|
"expect valid vector of changes for redo-changes"
|
|
(cpc/check-changes! redo-changes))
|
|
|
|
(dm/assert!
|
|
"expect valid vector of changes for undo-changes"
|
|
(cpc/check-changes! undo-changes))
|
|
|
|
(let [commit-id (or commit-id (uuid/next))
|
|
source (d/nilv source :local)
|
|
local? (= source :local)
|
|
commit {:id commit-id
|
|
:created-at (dt/now)
|
|
:source source
|
|
:origin (ptk/type origin)
|
|
:features features
|
|
:file-id file-id
|
|
:file-revn file-revn
|
|
:file-vern file-vern
|
|
:changes redo-changes
|
|
:redo-changes redo-changes
|
|
:undo-changes undo-changes
|
|
:save-undo? save-undo?
|
|
:undo-group undo-group
|
|
:tags tags
|
|
:stack-undo? stack-undo?}]
|
|
|
|
(ptk/reify ::commit
|
|
cljs.core/IDeref
|
|
(-deref [_] commit)
|
|
|
|
ptk/WatchEvent
|
|
(watch [_ state _]
|
|
(let [pending (when-not local?
|
|
(get-pending-commits state))]
|
|
(rx/concat
|
|
(rx/of (apply-changes-localy commit pending))
|
|
(if pending
|
|
(rx/concat
|
|
(->> (rx/from (reverse pending))
|
|
(rx/map (fn [commit] (update-indexes commit :undo-changes))))
|
|
(rx/of (update-indexes commit :redo-changes))
|
|
(->> (rx/from pending)
|
|
(rx/map (fn [commit] (update-indexes commit :redo-changes)))))
|
|
(rx/of (update-indexes commit :redo-changes)))))))))
|
|
|
|
(defn- resolve-file-revn
|
|
[state file-id]
|
|
(let [file (:workspace-file state)]
|
|
(if (= (:id file) file-id)
|
|
(:revn file)
|
|
(dm/get-in state [:libraries file-id :revn]))))
|
|
|
|
(defn- resolve-file-vern
|
|
[state file-id]
|
|
(let [file (:workspace-file state)]
|
|
(if (= (:id file) file-id)
|
|
(:vern file)
|
|
(dm/get-in state [:libraries file-id :vern]))))
|
|
|
|
(defn commit-changes
|
|
"Schedules a list of changes to execute now, and add the corresponding undo changes to
|
|
the undo stack.
|
|
|
|
Options:
|
|
- save-undo?: if set to false, do not add undo changes.
|
|
- undo-group: if some consecutive changes (or even transactions) share the same
|
|
undo-group, they will be undone or redone in a single step
|
|
"
|
|
[{:keys [redo-changes undo-changes save-undo? undo-group tags stack-undo? file-id]
|
|
:or {save-undo? true
|
|
stack-undo? false
|
|
undo-group (uuid/next)
|
|
tags #{}}
|
|
:as params}]
|
|
(ptk/reify ::commit-changes
|
|
ptk/WatchEvent
|
|
(watch [_ state _]
|
|
(let [file-id (or file-id (:current-file-id state))
|
|
uchg (vec undo-changes)
|
|
rchg (vec redo-changes)
|
|
features (features/get-team-enabled-features state)
|
|
permissions (:permissions state)]
|
|
|
|
;; Prevent commit changes by a viewer team member (it really should never happen)
|
|
(when (:can-edit permissions)
|
|
(rx/of (-> params
|
|
(assoc :undo-group undo-group)
|
|
(assoc :features features)
|
|
(assoc :tags tags)
|
|
(assoc :stack-undo? stack-undo?)
|
|
(assoc :save-undo? save-undo?)
|
|
(assoc :file-id file-id)
|
|
(assoc :file-revn (resolve-file-revn state file-id))
|
|
(assoc :file-vern (resolve-file-vern state file-id))
|
|
(assoc :undo-changes uchg)
|
|
(assoc :redo-changes rchg)
|
|
(commit))))))))
|