mirror of
https://github.com/penpot/penpot.git
synced 2026-01-03 11:58:46 -05:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e72e812166 | ||
|
|
65a00aa13f | ||
|
|
acc0623219 | ||
|
|
990a948bcc | ||
|
|
4b6d3546e0 | ||
|
|
0bd3d80816 | ||
|
|
a261a57868 | ||
|
|
af389fe63a | ||
|
|
defcef3e59 |
@@ -150,8 +150,8 @@
|
||||
[["" {:middleware [[mw/server-timing]
|
||||
[mw/params]
|
||||
[mw/format-response]
|
||||
[mw/errors errors/handle]
|
||||
[mw/parse-request]
|
||||
[mw/errors errors/handle]
|
||||
[session/soft-auth cfg]
|
||||
[actoken/soft-auth cfg]
|
||||
[mw/restrict-methods]]}
|
||||
|
||||
@@ -14,32 +14,28 @@
|
||||
[app.http :as-alias http]
|
||||
[app.http.access-token :as-alias actoken]
|
||||
[app.http.session :as-alias session]
|
||||
[app.util.inet :as inet]
|
||||
[clojure.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
[ring.request :as rreq]
|
||||
[ring.response :as rres]))
|
||||
|
||||
(defn- parse-client-ip
|
||||
[request]
|
||||
(or (some-> (rreq/get-header request "x-forwarded-for") (str/split ",") first)
|
||||
(rreq/get-header request "x-real-ip")
|
||||
(rreq/remote-addr request)))
|
||||
|
||||
(defn request->context
|
||||
"Extracts error report relevant context data from request."
|
||||
[request]
|
||||
(let [claims (-> {}
|
||||
(into (::session/token-claims request))
|
||||
(into (::actoken/token-claims request)))]
|
||||
|
||||
{:request/path (:path request)
|
||||
:request/method (:method request)
|
||||
:request/params (:params request)
|
||||
:request/user-agent (rreq/get-header request "user-agent")
|
||||
:request/ip-addr (parse-client-ip request)
|
||||
:request/ip-addr (inet/parse-request request)
|
||||
:request/profile-id (:uid claims)
|
||||
:version/frontend (or (rreq/get-header request "x-frontend-version") "unknown")
|
||||
:version/backend (:full cf/version)}))
|
||||
|
||||
|
||||
(defmulti handle-error
|
||||
(fn [cause _ _]
|
||||
(-> cause ex-data :type)))
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[app.common.logging :as l]
|
||||
[app.common.transit :as t]
|
||||
[app.config :as cf]
|
||||
[app.http.errors :as errors]
|
||||
[clojure.data.json :as json]
|
||||
[cuerdas.core :as str]
|
||||
[ring.request :as rreq]
|
||||
@@ -70,12 +71,12 @@
|
||||
:else
|
||||
request)))
|
||||
|
||||
(handle-error [cause]
|
||||
(handle-error [cause request]
|
||||
(cond
|
||||
(instance? RuntimeException cause)
|
||||
(if-let [cause (ex-cause cause)]
|
||||
(handle-error cause)
|
||||
(throw cause))
|
||||
(handle-error cause request)
|
||||
(errors/handle cause request))
|
||||
|
||||
(instance? RequestTooBigException cause)
|
||||
(ex/raise :type :validation
|
||||
@@ -89,14 +90,14 @@
|
||||
:cause cause)
|
||||
|
||||
:else
|
||||
(throw cause)))]
|
||||
(errors/handle cause request)))]
|
||||
|
||||
(fn [request]
|
||||
(if (= (rreq/method request) :post)
|
||||
(let [request (ex/try! (process-request request))]
|
||||
(if (ex/exception? request)
|
||||
(handle-error request)
|
||||
(handler request)))
|
||||
(try
|
||||
(-> request process-request handler)
|
||||
(catch Throwable cause
|
||||
(handle-error cause request)))
|
||||
(handler request)))))
|
||||
|
||||
(def parse-request
|
||||
|
||||
@@ -286,14 +286,17 @@
|
||||
(try
|
||||
(-> (db/insert! conn :profile params)
|
||||
(profile/decode-row))
|
||||
(catch org.postgresql.util.PSQLException e
|
||||
(let [state (.getSQLState e)]
|
||||
(catch org.postgresql.util.PSQLException cause
|
||||
(let [state (.getSQLState cause)]
|
||||
(if (not= state "23505")
|
||||
(throw e)
|
||||
(ex/raise :type :validation
|
||||
:code :email-already-exists
|
||||
:hint "email already exists"
|
||||
:cause e)))))))
|
||||
(throw cause)
|
||||
|
||||
(do
|
||||
(l/error :hint "not an error" :cause cause)
|
||||
(ex/raise :type :validation
|
||||
:code :email-already-exists
|
||||
:hint "email already exists"
|
||||
:cause cause))))))))
|
||||
|
||||
(defn create-profile-rels!
|
||||
[conn {:keys [id] :as profile}]
|
||||
|
||||
@@ -671,7 +671,7 @@
|
||||
f.modified_at,
|
||||
f.name,
|
||||
f.is_shared,
|
||||
ft.media_id,
|
||||
ft.media_id AS thumbnail_id,
|
||||
row_number() over w as row_num
|
||||
from file as f
|
||||
inner join project as p on (p.id = f.project_id)
|
||||
@@ -690,10 +690,8 @@
|
||||
[conn team-id]
|
||||
(->> (db/exec! conn [sql:team-recent-files team-id])
|
||||
(mapv (fn [row]
|
||||
(if-let [media-id (:media-id row)]
|
||||
(-> row
|
||||
(dissoc :media-id)
|
||||
(assoc :thumbnail-uri (resolve-public-uri media-id)))
|
||||
(if-let [media-id (:thumbnail-id row)]
|
||||
(assoc row :thumbnail-uri (resolve-public-uri media-id))
|
||||
(dissoc row :media-id))))))
|
||||
|
||||
(def ^:private schema:get-team-recent-files
|
||||
|
||||
@@ -406,4 +406,5 @@
|
||||
(when-not (db/read-only? conn)
|
||||
(let [cfg (update cfg ::sto/storage media/configure-assets-storage)
|
||||
media (create-file-thumbnail! cfg params)]
|
||||
{:uri (files/resolve-public-uri (:id media))})))))
|
||||
{:uri (files/resolve-public-uri (:id media))
|
||||
:id (:id media)})))))
|
||||
|
||||
@@ -670,52 +670,14 @@
|
||||
(ctyl/delete-typography data id))
|
||||
|
||||
;; === Operations
|
||||
|
||||
(defmethod process-operation :set
|
||||
[on-changed shape op]
|
||||
(let [attr (:attr op)
|
||||
group (get ctk/sync-attrs attr)
|
||||
val (:val op)
|
||||
shape-val (get shape attr)
|
||||
ignore (or (:ignore-touched op) (= attr :position-data)) ;; position-data is a derived attribute and
|
||||
ignore-geometry (:ignore-geometry op) ;; never triggers touched by itself
|
||||
is-geometry? (and (or (= group :geometry-group)
|
||||
(and (= group :content-group) (= (:type shape) :path)))
|
||||
(not (#{:width :height} attr))) ;; :content in paths are also considered geometric
|
||||
;; TODO: the check of :width and :height probably may be removed
|
||||
;; after the check added in data/workspace/modifiers/check-delta
|
||||
;; function. Better check it and test toroughly when activating
|
||||
;; components-v2 mode.
|
||||
in-copy? (ctk/in-component-copy? shape)
|
||||
|
||||
;; For geometric attributes, there are cases in that the value changes
|
||||
;; slightly (e.g. when rounding to pixel, or when recalculating text
|
||||
;; positions in different zoom levels). To take this into account, we
|
||||
;; ignore geometric changes smaller than 1 pixel.
|
||||
equal? (if is-geometry?
|
||||
(gsh/close-attrs? attr val shape-val 1)
|
||||
(gsh/close-attrs? attr val shape-val))]
|
||||
|
||||
;; Notify when value has changed, except when it has not moved relative to the
|
||||
;; component head.
|
||||
(when (and group (not equal?) (not (and ignore-geometry is-geometry?)))
|
||||
(on-changed shape))
|
||||
|
||||
(cond-> shape
|
||||
;; Depending on the origin of the attribute change, we need or not to
|
||||
;; set the "touched" flag for the group the attribute belongs to.
|
||||
;; In some cases we need to ignore touched only if the attribute is
|
||||
;; geometric (position, width or transformation).
|
||||
(and in-copy? group (not ignore) (not equal?)
|
||||
(not (and ignore-geometry is-geometry?)))
|
||||
(-> (update :touched cfh/set-touched-group group)
|
||||
(dissoc :remote-synced))
|
||||
|
||||
(nil? val)
|
||||
(dissoc attr)
|
||||
|
||||
(some? val)
|
||||
(assoc attr val))))
|
||||
(ctn/set-shape-attr shape
|
||||
(:attr op)
|
||||
(:val op)
|
||||
:on-changed on-changed
|
||||
:ignore-touched (:ignore-touched op)
|
||||
:ignore-geometry (:ignore-geometry op)))
|
||||
|
||||
(defmethod process-operation :set-touched
|
||||
[_ shape op]
|
||||
|
||||
@@ -357,15 +357,6 @@
|
||||
;; COMPONENTS HELPERS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn set-touched-group
|
||||
[touched group]
|
||||
(when group
|
||||
(conj (or touched #{}) group)))
|
||||
|
||||
(defn touched-group?
|
||||
[shape group]
|
||||
((or (:touched shape) #{}) group))
|
||||
|
||||
(defn make-container
|
||||
[page-or-component type]
|
||||
(assoc page-or-component :type type))
|
||||
|
||||
@@ -288,13 +288,23 @@
|
||||
(some? (:shape-ref ref-shape))
|
||||
(pcb/update-shapes [(:id shape)] #(assoc % :shape-ref (:shape-ref ref-shape)))
|
||||
|
||||
;; When advancing level, if the referenced shape has a swap slot, it must be
|
||||
;; copied to the current shape, because the shape-ref now will not be pointing
|
||||
;; to a near main (except for first level subcopies).
|
||||
;; When advancing level, the normal touched groups (not swap slots) of the
|
||||
;; ref-shape must be merged into the current shape, because they refer to
|
||||
;; the new referenced shape.
|
||||
(some? ref-shape)
|
||||
(pcb/update-shapes
|
||||
[(:id shape)]
|
||||
#(assoc % :touched
|
||||
(clojure.set/union (:touched shape)
|
||||
(ctk/normal-touched-groups ref-shape))))
|
||||
|
||||
;; Swap slot must also be copied if the current shape has not any,
|
||||
;; except if this is the first level subcopy.
|
||||
(and (some? (ctk/get-swap-slot ref-shape))
|
||||
(nil? (ctk/get-swap-slot shape))
|
||||
(not= (:id shape) shape-id))
|
||||
(pcb/update-shapes [(:id shape)] #(ctk/set-swap-slot % (ctk/get-swap-slot ref-shape))))))]
|
||||
|
||||
(reduce skip-near changes children)))
|
||||
|
||||
(defn prepare-restore-component
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.colors-list :as ctcl]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.shape :as cts]
|
||||
@@ -69,6 +70,19 @@
|
||||
(thf/current-page file))]
|
||||
(ctst/get-shape page id)))
|
||||
|
||||
(defn update-shape
|
||||
[file shape-label attr val & {:keys [page-label]}]
|
||||
(let [page (if page-label
|
||||
(thf/get-page file page-label)
|
||||
(thf/current-page file))
|
||||
shape (ctst/get-shape page (thi/id shape-label))]
|
||||
(ctf/update-file-data
|
||||
file
|
||||
(fn [file-data]
|
||||
(ctpl/update-page file-data
|
||||
(:id page)
|
||||
#(ctst/set-shape % (ctn/set-shape-attr shape attr val)))))))
|
||||
|
||||
(defn sample-color
|
||||
[label & {:keys [] :as params}]
|
||||
(ctc/make-color (assoc params :id (thi/new-id! label))))
|
||||
|
||||
@@ -202,6 +202,11 @@
|
||||
[group]
|
||||
(str/starts-with? (name group) "swap-slot-"))
|
||||
|
||||
(defn normal-touched-groups
|
||||
"Gets all touched groups that are not swap slots."
|
||||
[shape]
|
||||
(into #{} (remove swap-slot? (:touched shape))))
|
||||
|
||||
(defn group->swap-slot
|
||||
[group]
|
||||
(uuid/uuid (subs (name group) 10)))
|
||||
|
||||
@@ -498,7 +498,7 @@
|
||||
; original component doesn't exist or is deleted. So for this function purposes, they
|
||||
; are removed from the list
|
||||
remove? (fn [shape]
|
||||
(let [component (get-in libraries [(:component-file shape) :data :components (:component-id shape)])]
|
||||
(let [component (get-in libraries [(:component-file shape) :data :components (:component-id shape)])]
|
||||
(and component (not (:deleted component)))))
|
||||
|
||||
selected-components (cond->> (mapcat collect-main-shapes children objects)
|
||||
@@ -534,3 +534,48 @@
|
||||
(if (or no-changes? (not (invalid-structure-for-component? objects parent children pasting? libraries)))
|
||||
[parent-id (get-frame parent-id)]
|
||||
(recur (:parent-id parent) objects children pasting? libraries))))))
|
||||
|
||||
;; --- SHAPE UPDATE
|
||||
|
||||
(defn set-shape-attr
|
||||
[shape attr val & {:keys [on-changed ignore-touched ignore-geometry]}]
|
||||
(let [group (get ctk/sync-attrs attr)
|
||||
shape-val (get shape attr)
|
||||
ignore (or ignore-touched (= attr :position-data)) ;; position-data is a derived attribute and
|
||||
is-geometry? (and (or (= group :geometry-group) ;; never triggers touched by itself
|
||||
(and (= group :content-group) (= (:type shape) :path)))
|
||||
(not (#{:width :height} attr))) ;; :content in paths are also considered geometric
|
||||
;; TODO: the check of :width and :height probably may be removed
|
||||
;; after the check added in data/workspace/modifiers/check-delta
|
||||
;; function. Better check it and test toroughly when activating
|
||||
;; components-v2 mode.
|
||||
in-copy? (ctk/in-component-copy? shape)
|
||||
|
||||
;; For geometric attributes, there are cases in that the value changes
|
||||
;; slightly (e.g. when rounding to pixel, or when recalculating text
|
||||
;; positions in different zoom levels). To take this into account, we
|
||||
;; ignore geometric changes smaller than 1 pixel.
|
||||
equal? (if is-geometry?
|
||||
(gsh/close-attrs? attr val shape-val 1)
|
||||
(gsh/close-attrs? attr val shape-val))]
|
||||
|
||||
;; Notify when value has changed, except when it has not moved relative to the
|
||||
;; component head.
|
||||
(when (and on-changed group (not equal?) (not (and ignore-geometry is-geometry?)))
|
||||
(on-changed shape))
|
||||
|
||||
(cond-> shape
|
||||
;; Depending on the origin of the attribute change, we need or not to
|
||||
;; set the "touched" flag for the group the attribute belongs to.
|
||||
;; In some cases we need to ignore touched only if the attribute is
|
||||
;; geometric (position, width or transformation).
|
||||
(and in-copy? group (not ignore) (not equal?)
|
||||
(not (and ignore-geometry is-geometry?)))
|
||||
(-> (update :touched ctk/set-touched-group group)
|
||||
(dissoc :remote-synced))
|
||||
|
||||
(nil? val)
|
||||
(dissoc attr)
|
||||
|
||||
(some? val)
|
||||
(assoc attr val))))
|
||||
|
||||
@@ -501,8 +501,8 @@
|
||||
(assoc :proportion-lock true)))
|
||||
|
||||
(defn setup-shape
|
||||
"A function that initializes the geometric data of
|
||||
the shape. The props must have :x :y :width :height."
|
||||
"A function that initializes the geometric data of the shape. The props must
|
||||
contain at least :x :y :width :height."
|
||||
[{:keys [type] :as props}]
|
||||
(let [shape (make-minimal-shape type)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns common-tests.logic.comp-detach-with-swap-test
|
||||
(ns common-tests.logic.comp-detach-with-nested-test
|
||||
(:require
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.logic.libraries :as cll]
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
(t/use-fixtures :each thi/test-fixture)
|
||||
|
||||
;; Related .penpot file: common/test/cases/detach-with-swap.penpot
|
||||
;; Related .penpot file: common/test/cases/detach-with-nested.penpot
|
||||
(defn- setup-file
|
||||
[]
|
||||
;; {:r-ellipse} [:name Ellipse, :type :frame] # [Component :c-ellipse]
|
||||
@@ -195,3 +195,177 @@
|
||||
(t/is (= (:shape-ref copy-nested-rectangle) (thi/id :rectangle)))
|
||||
(t/is (nil? (ctk/get-swap-slot copy-nested-rectangle)))))
|
||||
|
||||
(t/deftest test-propagate-touched
|
||||
(let [;; ==== Setup
|
||||
file (-> (setup-file)
|
||||
(ths/update-shape :nested2-ellipse :fills (ths/sample-fills-color :fill-color "#fabada"))
|
||||
(thc/instantiate-component :c-big-board
|
||||
:copy-big-board
|
||||
:children-labels [:copy-h-board-with-ellipse
|
||||
:copy-nested2-h-ellipse
|
||||
:copy-nested2-ellipse]))
|
||||
|
||||
page (thf/current-page file)
|
||||
nested2-ellipse (ths/get-shape file :nested2-ellipse)
|
||||
copy-nested2-ellipse (ths/get-shape file :copy-nested2-ellipse)
|
||||
|
||||
;; ==== Action
|
||||
changes (cll/generate-detach-instance (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects (:objects page)))
|
||||
page
|
||||
{(:id file) file}
|
||||
(thi/id :copy-big-board))
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
nested2-ellipse' (ths/get-shape file' :nested2-ellipse)
|
||||
copy-nested2-ellipse' (ths/get-shape file' :copy-nested2-ellipse)
|
||||
fills' (:fills copy-nested2-ellipse')
|
||||
fill' (first fills')]
|
||||
|
||||
;; ==== Check
|
||||
|
||||
;; The touched group must be propagated to the copy, because now this copy
|
||||
;; has the original ellipse component as near main, but its attributes have
|
||||
;; been inherited from the ellipse inside big-board.
|
||||
(t/is (= (:touched nested2-ellipse) #{:fill-group}))
|
||||
(t/is (= (:touched copy-nested2-ellipse) nil))
|
||||
(t/is (= (:touched nested2-ellipse') #{:fill-group}))
|
||||
(t/is (= (:touched copy-nested2-ellipse') #{:fill-group}))
|
||||
(t/is (= (count fills') 1))
|
||||
(t/is (= (:fill-color fill') "#fabada"))
|
||||
(t/is (= (:fill-opacity fill') 1))))
|
||||
|
||||
(t/deftest test-merge-touched
|
||||
(let [;; ==== Setup
|
||||
file (-> (setup-file)
|
||||
(ths/update-shape :nested2-ellipse :fills (ths/sample-fills-color :fill-color "#fabada"))
|
||||
(thc/instantiate-component :c-big-board
|
||||
:copy-big-board
|
||||
:children-labels [:copy-h-board-with-ellipse
|
||||
:copy-nested2-h-ellipse
|
||||
:copy-nested2-ellipse])
|
||||
(ths/update-shape :copy-nested2-ellipse :name "Modified name")
|
||||
(ths/update-shape :copy-nested2-ellipse :fills (ths/sample-fills-color :fill-color "#abcdef")))
|
||||
|
||||
page (thf/current-page file)
|
||||
nested2-ellipse (ths/get-shape file :nested2-ellipse)
|
||||
copy-nested2-ellipse (ths/get-shape file :copy-nested2-ellipse)
|
||||
|
||||
;; ==== Action
|
||||
changes (cll/generate-detach-instance (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects (:objects page)))
|
||||
page
|
||||
{(:id file) file}
|
||||
(thi/id :copy-big-board))
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
nested2-ellipse' (ths/get-shape file' :nested2-ellipse)
|
||||
copy-nested2-ellipse' (ths/get-shape file' :copy-nested2-ellipse)
|
||||
fills' (:fills copy-nested2-ellipse')
|
||||
fill' (first fills')]
|
||||
|
||||
;; ==== Check
|
||||
|
||||
;; If the copy have been already touched, merge the groups and preserve the modifications.
|
||||
(t/is (= (:touched nested2-ellipse) #{:fill-group}))
|
||||
(t/is (= (:touched copy-nested2-ellipse) #{:name-group :fill-group}))
|
||||
(t/is (= (:touched nested2-ellipse') #{:fill-group}))
|
||||
(t/is (= (:touched copy-nested2-ellipse') #{:name-group :fill-group}))
|
||||
(t/is (= (count fills') 1))
|
||||
(t/is (= (:fill-color fill') "#abcdef"))
|
||||
(t/is (= (:fill-opacity fill') 1))))
|
||||
|
||||
(t/deftest test-dont-propagete-touched-when-swapped-copy
|
||||
(let [;; ==== Setup
|
||||
file (-> (setup-file)
|
||||
(ths/update-shape :nested-rectangle :fills (ths/sample-fills-color :fill-color "#fabada"))
|
||||
(thc/instantiate-component :c-big-board
|
||||
:copy-big-board
|
||||
:children-labels [:copy-h-board-with-ellipse
|
||||
:copy-nested2-h-ellipse
|
||||
:copy-nested2-ellipse])
|
||||
(thc/component-swap :copy-h-board-with-ellipse
|
||||
:c-board-with-rectangle
|
||||
:copy-h-board-with-rectangle
|
||||
:children-labels [:copy-nested2-h-rectangle
|
||||
:copy-nested2-rectangle]))
|
||||
|
||||
page (thf/current-page file)
|
||||
nested2-rectangle (ths/get-shape file :nested2-rectangle)
|
||||
copy-nested2-rectangle (ths/get-shape file :copy-nested2-rectangle)
|
||||
|
||||
;; ==== Action
|
||||
changes (cll/generate-detach-instance (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects (:objects page)))
|
||||
page
|
||||
{(:id file) file}
|
||||
(thi/id :copy-big-board))
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
nested2-rectangle' (ths/get-shape file' :nested2-rectangle)
|
||||
copy-nested2-rectangle' (ths/get-shape file' :copy-nested2-rectangle)
|
||||
fills' (:fills copy-nested2-rectangle')
|
||||
fill' (first fills')]
|
||||
|
||||
;; ==== Check
|
||||
|
||||
;; If the copy has been swapped, there is nothing to propagate since it's already
|
||||
;; pointing to the swapped near main.
|
||||
(t/is (= (:touched nested2-rectangle) nil))
|
||||
(t/is (= (:touched copy-nested2-rectangle) nil))
|
||||
(t/is (= (:touched nested2-rectangle') nil))
|
||||
(t/is (= (:touched copy-nested2-rectangle') nil))
|
||||
(t/is (= (count fills') 1))
|
||||
(t/is (= (:fill-color fill') "#fabada"))
|
||||
(t/is (= (:fill-opacity fill') 1))))
|
||||
|
||||
(t/deftest test-propagate-touched-when-swapped-main
|
||||
(let [;; ==== Setup
|
||||
file (-> (setup-file)
|
||||
(thc/component-swap :nested2-h-ellipse
|
||||
:c-rectangle
|
||||
:nested2-h-rectangle
|
||||
:children-labels [:nested2-rectangle])
|
||||
(ths/update-shape :nested2-rectangle :fills (ths/sample-fills-color :fill-color "#fabada"))
|
||||
(thc/instantiate-component :c-big-board
|
||||
:copy-big-board
|
||||
:children-labels [:copy-h-board-with-ellipse
|
||||
:copy-nested2-h-rectangle
|
||||
:copy-nested2-rectangle]))
|
||||
|
||||
page (thf/current-page file)
|
||||
nested2-rectangle (ths/get-shape file :nested2-rectangle)
|
||||
copy-nested2-rectangle (ths/get-shape file :copy-nested2-rectangle)
|
||||
|
||||
;; ==== Action
|
||||
changes (cll/generate-detach-instance (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects (:objects page)))
|
||||
page
|
||||
{(:id file) file}
|
||||
(thi/id :copy-big-board))
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
nested2-rectangle' (ths/get-shape file' :nested2-rectangle)
|
||||
copy-nested2-rectangle' (ths/get-shape file' :copy-nested2-rectangle)
|
||||
fills' (:fills copy-nested2-rectangle')
|
||||
fill' (first fills')]
|
||||
|
||||
;; ==== Check
|
||||
|
||||
;; If the main has been swapped, there is no difference. It propagates the same as
|
||||
;; if it were the original component.
|
||||
(t/is (= (:touched nested2-rectangle) #{:fill-group}))
|
||||
(t/is (= (:touched copy-nested2-rectangle) nil))
|
||||
(t/is (= (:touched nested2-rectangle') #{:fill-group}))
|
||||
(t/is (= (:touched copy-nested2-rectangle') #{:fill-group}))
|
||||
(t/is (= (count fills') 1))
|
||||
(t/is (= (:fill-color fill') "#fabada"))
|
||||
(t/is (= (:fill-opacity fill') 1))))
|
||||
@@ -898,8 +898,7 @@
|
||||
(-> state
|
||||
(d/update-in-when [:dashboard-files id :is-shared] (constantly is-shared))
|
||||
(d/update-in-when [:dashboard-recent-files id :is-shared] (constantly is-shared))
|
||||
(cond->
|
||||
(not is-shared)
|
||||
(cond-> (not is-shared)
|
||||
(d/update-when :dashboard-shared-files dissoc id))))
|
||||
|
||||
ptk/WatchEvent
|
||||
@@ -909,7 +908,7 @@
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn set-file-thumbnail
|
||||
[file-id thumbnail-uri]
|
||||
[file-id thumbnail-id]
|
||||
(ptk/reify ::set-file-thumbnail
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
@@ -917,10 +916,10 @@
|
||||
(->> files
|
||||
(mapv #(cond-> %
|
||||
(= file-id (:id %))
|
||||
(assoc :thumbnail-uri thumbnail-uri)))))]
|
||||
(assoc :thumbnail-id thumbnail-id)))))]
|
||||
(-> state
|
||||
(d/update-in-when [:dashboard-files file-id] assoc :thumbnail-uri thumbnail-uri)
|
||||
(d/update-in-when [:dashboard-recent-files file-id] assoc :thumbnail-uri thumbnail-uri)
|
||||
(d/update-in-when [:dashboard-files file-id] assoc :thumbnail-id thumbnail-id)
|
||||
(d/update-in-when [:dashboard-recent-files file-id] assoc :thumbnail-id thumbnail-id)
|
||||
(d/update-when :dashboard-search-result update-search-files))))))
|
||||
|
||||
;; --- EVENT: create-file
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.changes :as dch]
|
||||
[app.main.repo :as rp]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
@@ -131,8 +130,7 @@
|
||||
(rx/concat
|
||||
(if (= :authentication (:type cause))
|
||||
(rx/empty)
|
||||
(rx/of (rt/assign-exception cause)
|
||||
(ptk/data-event ::error cause)
|
||||
(rx/of (ptk/data-event ::error cause)
|
||||
(update-status :error)))
|
||||
(rx/of (discard-persistence-state))
|
||||
(rx/throw cause))))))))))
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.logging :as log]
|
||||
[app.config :as cf]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.features :as features]
|
||||
@@ -47,7 +48,7 @@
|
||||
[file-id revn blob]
|
||||
(let [params {:file-id file-id :revn revn :media blob}]
|
||||
(->> (rp/cmd! :create-file-thumbnail params)
|
||||
(rx/map :uri))))
|
||||
(rx/map :id))))
|
||||
|
||||
(defn render-thumbnail
|
||||
[file-id revn]
|
||||
@@ -71,15 +72,15 @@
|
||||
|
||||
(mf/defc grid-item-thumbnail
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [file-id revn thumbnail-uri background-color]}]
|
||||
[{:keys [file-id revn thumbnail-id background-color]}]
|
||||
(let [container (mf/use-ref)
|
||||
visible? (h/use-visible container :once? true)]
|
||||
|
||||
(mf/with-effect [file-id revn visible? thumbnail-uri]
|
||||
(when (and visible? (not thumbnail-uri))
|
||||
(mf/with-effect [file-id revn visible? thumbnail-id]
|
||||
(when (and visible? (not thumbnail-id))
|
||||
(->> (ask-for-thumbnail file-id revn)
|
||||
(rx/subs! (fn [url]
|
||||
(st/emit! (dd/set-file-thumbnail file-id url)))
|
||||
(rx/subs! (fn [thumbnail-id]
|
||||
(st/emit! (dd/set-file-thumbnail file-id thumbnail-id)))
|
||||
(fn [cause]
|
||||
(log/error :hint "unable to render thumbnail"
|
||||
:file-if file-id
|
||||
@@ -90,9 +91,9 @@
|
||||
:style {:background-color background-color}
|
||||
:ref container}
|
||||
(when visible?
|
||||
(if thumbnail-uri
|
||||
(if thumbnail-id
|
||||
[:img {:class (stl/css :grid-item-thumbnail-image)
|
||||
:src thumbnail-uri
|
||||
:src (cf/resolve-media thumbnail-id)
|
||||
:loading "lazy"
|
||||
:decoding "async"}]
|
||||
i/loader-pencil))]))
|
||||
@@ -365,7 +366,7 @@
|
||||
[:& grid-item-thumbnail
|
||||
{:file-id (:id file)
|
||||
:revn (:revn file)
|
||||
:thumbnail-uri (:thumbnail-uri file)
|
||||
:thumbnail-id (:thumbnail-id file)
|
||||
:background-color (dm/get-in file [:data :options :background])}])
|
||||
|
||||
(when (and (:is-shared file) (not library-view?))
|
||||
|
||||
Reference in New Issue
Block a user