diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj index a3253085c..ed6feaa26 100644 --- a/backend/src/app/rpc/commands/comments.clj +++ b/backend/src/app/rpc/commands/comments.clj @@ -47,31 +47,28 @@ (str/join ""))) (defn- format-comment-url - [thread {:keys [team-id file-id page-id]}] + [thread file] (str/ffmt "%/#/workspace?%" (cf/get :public-uri) (uri/map->query-string - {:file-id file-id - :page-id page-id - :team-id team-id + {:file-id (:id file) + :page-id (:page-id file) + :team-id (:team-id file) :comment-id (:id thread)}))) (defn- format-comment-ref - [{:keys [seqn]} {:keys [file-name page-name]}] - (str/ffmt "#%, %, %" seqn file-name page-name)) + [thread file] + (str/ffmt "#%, %, %" + (:seqn thread) + (:name file) + (:page-name file))) -(defn get-team-users +(defn- get-team-users [conn team-id] (->> (teams/get-users+props conn team-id) (map profile/decode-row) (d/index-by :id))) -(defn- resolve-profile-name - [conn profile-id] - (-> (db/get conn :profile {:id profile-id} - {::sql/columns [:fullname]}) - (get :fullname))) - (defn- notification-email? [profile-id owner-id props] (if (= profile-id owner-id) @@ -83,24 +80,22 @@ (not= :none (-> props :notifications :email-comments))) (defn send-comment-emails! - [conn {:keys [profile-id team-id] :as params} comment thread] - - (let [team-users (get-team-users conn team-id) - source-user (resolve-profile-name conn profile-id) - - comment-reference (format-comment-ref thread params) + [conn profile comment thread file] + (let [team-users (get-team-users conn (:team-id file)) + comment-reference (format-comment-ref thread file) comment-content (format-comment comment) - comment-url (format-comment-url thread params) + comment-url (format-comment-url thread file) + profile-id (get profile :id) ;; Users mentioned in this comment comment-mentions (-> (:mentions comment) - (set/difference #{profile-id})) + (disj profile-id)) ;; Users mentioned in this thread thread-mentions (-> (:mentions thread) - ;; Remove the mentions in the thread because we're already sending a + ;; Remove the mentions in the comment because we're already sending a ;; notification (set/difference comment-mentions) (disj profile-id)) @@ -118,9 +113,10 @@ (eml/send! {::eml/conn conn ::eml/factory eml/comment-mention + :public-uri (cf/get :public-uri) :to email :name fullname - :source-user source-user + :source-user (:fullname profile) :comment-reference comment-reference :comment-content comment-content :comment-url comment-url})))) @@ -132,9 +128,10 @@ (eml/send! {::eml/conn conn ::eml/factory eml/comment-thread + :public-uri (cf/get :public-uri) :to email :name fullname - :source-user source-user + :source-user (:fullname profile) :comment-reference comment-reference :comment-content comment-content :comment-url comment-url})))) @@ -146,9 +143,10 @@ (eml/send! {::eml/conn conn ::eml/factory eml/comment-notification + :public-uri (cf/get :public-uri) :to email :name fullname - :source-user source-user + :source-user (:fullname profile) :comment-reference comment-reference :comment-content comment-content :comment-url comment-url})))))) @@ -165,12 +163,13 @@ (def ^:private sql:get-file - "select f.id, f.modified_at, f.revn, f.features, f.name, - f.project_id, p.team_id, f.data - from file as f - join project as p on (p.id = f.project_id) - where f.id = ? - and f.deleted_at is null") + "SELECT f.id, f.modified_at, f.revn, f.features, f.name, + f.project_id, p.team_id, f.data, + f.data_ref_id, f.data_backend + FROM file as f + INNER JOIN project as p on (p.id = f.project_id) + WHERE f.id = ? + AND (f.deleted_at IS NULL OR f.deleted_at > now())") (defn- get-file "A specialized version of get-file for comments module." @@ -182,12 +181,16 @@ :hint "file not found")) (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg file-id)] - (let [{:keys [data] :as file} (files/decode-row file)] + (let [file (->> file + (files/decode-row) + (feat.fdata/resolve-file-data cfg)) + data (get file :data)] (-> file (assoc :page-name (dm/get-in data [:pages-index page-id :name])) (assoc :page-id page-id) (dissoc :data)))))) +;; FIXME: rename (defn- get-comment-thread [conn thread-id & {:as opts}] (-> (db/get-by-id conn :comment-thread thread-id opts) @@ -249,6 +252,9 @@ (def ^:private sql:comment-threads "SELECT DISTINCT ON (ct.id) ct.*, + pf.fullname AS owner_fullname, + pf.email AS owner_email, + pf.photo_id AS owner_photo_id, p.team_id AS team_id, f.name AS file_name, f.project_id AS project_id, @@ -265,6 +271,7 @@ INNER JOIN file AS f ON (f.id = ct.file_id) INNER JOIN project AS p ON (p.id = f.project_id) LEFT JOIN comment_thread_status AS cts ON (cts.thread_id = ct.id AND cts.profile_id = ?) + LEFT JOIN profile AS pf ON (ct.owner_id = pf.id) WINDOW w AS (PARTITION BY c.thread_id ORDER BY c.created_at ASC)") (def ^:private sql:comment-threads-by-file-id @@ -360,15 +367,25 @@ ::sm/params schema:get-comments} [cfg {:keys [::rpc/profile-id thread-id share-id]}] (db/run! cfg (fn [{:keys [::db/conn]}] - (let [{:keys [file-id] :as thread} (get-comment-thread conn thread-id)] + (let [{:keys [file-id]} (get-comment-thread conn thread-id)] (files/check-comment-permissions! conn profile-id file-id share-id) (get-comments conn thread-id))))) +(def sql:get-comments + "SELECT c.*, + ct.file_id AS file_id, + pf.fullname AS owner_fullname, + pf.email AS owner_email, + pf.photo_id AS owner_photo_id + FROM comment AS c + INNER JOIN comment_thread AS ct ON (ct.id = c.thread_id) + LEFT JOIN profile AS pf ON (c.owner_id = pf.id) + WHERE c.thread_id = ? + ORDER BY c.created_at ASC") + (defn- get-comments [conn thread-id] - (->> (db/query conn :comment - {:thread-id thread-id} - {:order-by [[:created-at :asc]]}) + (->> (db/exec! conn [sql:get-comments thread-id]) (into [] xf-decode-row))) ;; --- COMMAND: Get file comments users @@ -429,7 +446,21 @@ [:page-id ::sm/uuid] [:frame-id ::sm/uuid] [:share-id {:optional true} [:maybe ::sm/uuid]] - [:mentions {:optional true} [:vector ::sm/uuid]]]) + [:mentions {:optional true} [::sm/set ::sm/uuid]]]) + +(defn- update-thread-seqn + [conn file-id seqn] + (db/update! conn :file + {:comment-thread-seqn seqn} + {:id file-id} + {::db/return-keys false})) + +(defn add-owner + [thread-or-comment profile] + (-> thread-or-comment + (assoc :owner-fullname (:fullname profile)) + (assoc :owner-email (:email profile)) + (assoc :owner-photo-id (:photo-id profile)))) (sv/defmethod ::create-comment-thread {::doc/added "1.15" @@ -437,10 +468,10 @@ ::rtry/enabled true ::rtry/when rtry/conflict-exception? ::sm/params schema:create-comment-thread} - [cfg {:keys [::rpc/profile-id ::rpc/request-at file-id page-id share-id mentions position content frame-id]}] + [cfg {:keys [::rpc/profile-id file-id page-id share-id] :as params}] (files/check-comment-permissions! cfg profile-id file-id share-id) - (let [{:keys [team-id project-id page-name name]} (get-file cfg file-id page-id)] + (let [{:keys [team-id project-id] :as file} (get-file cfg file-id page-id)] (-> cfg (assoc ::quotes/profile-id profile-id) (assoc ::quotes/team-id team-id) @@ -449,26 +480,14 @@ (quotes/check! {::quotes/id ::quotes/comment-threads-per-file} {::quotes/id ::quotes/comments-per-file})) - (let [params {:created-at request-at - :profile-id profile-id - :file-id file-id - :file-name name - :page-id page-id - :page-name page-name - :position position - :content content - :frame-id frame-id - :team-id team-id - :project-id project-id - :mentions mentions} - thread (-> (db/tx-run! cfg create-comment-thread params) - (decode-row))] + (let [params (assoc params ::file file) + thread (db/tx-run! cfg create-comment-thread params)] (vary-meta thread assoc ::audit/props thread)))) (defn- create-comment-thread [{:keys [::db/conn] :as cfg} - {:keys [profile-id file-id page-id page-name created-at position content mentions frame-id] :as params}] + {:keys [::rpc/profile-id ::rpc/request-at ::file position content mentions frame-id] :as params}] (let [;; NOTE: we take the next seq number from a separate query ;; because we need to lock the file for avoid race conditions @@ -479,46 +498,47 @@ ;; different storage (example: redis) for alivate the update ;; pression on the file table - seqn (get-next-seqn conn file-id) + profile (profile/get-profile conn profile-id) + seqn (get-next-seqn conn (:id file)) + + file-id (get file :id) thread-id (uuid/next) + thread (-> (db/insert! conn :comment-thread {:id thread-id :file-id file-id + :page-name (:page-name file) + :page-id (:page-id file) :owner-id profile-id :participants (db/tjson #{profile-id}) - :page-name page-name - :page-id page-id - :created-at created-at - :modified-at created-at + :created-at request-at + :modified-at request-at :seqn seqn - :position (db/pgpoint position) :frame-id frame-id + :position (db/pgpoint position) :mentions (db/encode-pgarray mentions conn "uuid")}) (decode-row)) comment (-> (db/insert! conn :comment {:id (uuid/next) :thread-id thread-id :owner-id profile-id - :created-at created-at - :modified-at created-at + :created-at request-at + :modified-at request-at :mentions (db/encode-pgarray mentions conn "uuid") :content content}) (decode-row))] ;; Make the current thread as read. - (upsert-comment-thread-status! conn profile-id thread-id created-at) + (upsert-comment-thread-status! conn profile-id thread-id request-at) ;; Optimistic update of current seq number on file. - (db/update! conn :file - {:comment-thread-seqn seqn} - {:id file-id} - {::db/return-keys false}) + (update-thread-seqn conn file-id seqn) ;; Send mentions emails - (send-comment-emails! conn params comment thread) + (send-comment-emails! conn profile comment thread file) (-> thread - (select-keys [:id :file-id :page-id :mentions]) + (add-owner profile) (assoc :comment-id (:id comment))))) ;; --- COMMAND: Update Comment Thread Status @@ -534,7 +554,7 @@ ::sm/params schema:update-comment-thread-status ::db/transaction true} [{:keys [::db/conn]} {:keys [::rpc/profile-id id share-id]}] - (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)] + (let [{:keys [file-id]} (get-comment-thread conn id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) (upsert-comment-thread-status! conn profile-id id))) @@ -552,7 +572,7 @@ ::sm/params schema:update-comment-thread ::db/transaction true} [{:keys [::db/conn]} {:keys [::rpc/profile-id id is-resolved share-id]}] - (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)] + (let [{:keys [file-id]} (get-comment-thread conn id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) (db/update! conn :comment-thread {:is-resolved is-resolved} @@ -561,15 +581,13 @@ ;; --- COMMAND: Add Comment -(declare ^:private get-comment-thread) - (def ^:private schema:create-comment [:map {:title "create-comment"} [:thread-id ::sm/uuid] [:content [:string {:max 250}]] [:share-id {:optional true} [:maybe ::sm/uuid]] - [:mentions {:optional true} [:vector ::sm/uuid]]]) + [:mentions {:optional true} [::sm/set ::sm/uuid]]]) (sv/defmethod ::create-comment {::doc/added "1.15" @@ -577,65 +595,58 @@ ::sm/params schema:create-comment ::db/transaction true} [{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id ::rpc/request-at thread-id share-id content mentions]}] - (let [{:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true) - {file-name :name :keys [team-id project-id page-name] :as file} (get-file cfg file-id page-id)] + (let [{:keys [file-id page-id] :as thread} + (get-comment-thread conn thread-id ::sql/for-update true) + + {:keys [team-id project-id] :as file} + (get-file cfg file-id page-id)] (files/check-comment-permissions! conn profile-id file-id share-id) + (quotes/check! cfg {::quotes/id ::quotes/comments-per-file ::quotes/profile-id profile-id ::quotes/team-id team-id ::quotes/project-id project-id ::quotes/file-id file-id}) - ;; Update the page-name cached attribute on comment thread table. - (when (not= page-name (:page-name thread)) - (db/update! conn :comment-thread - {:page-name page-name} - {:id thread-id})) + (let [profile (profile/get-profile conn profile-id) + mentions (into #{} mentions) + params {:id (uuid/next) + :created-at request-at + :modified-at request-at + :thread-id thread-id + :owner-id profile-id + :content content + :mentions (db/encode-pgarray mentions conn "uuid")} - (let [comment (-> (db/insert! - conn :comment - {:id (uuid/next) - :created-at request-at - :modified-at request-at - :thread-id thread-id - :owner-id profile-id - :content content - :mentions - (-> mentions - (set) - (db/encode-pgarray conn "uuid"))}) - (decode-row)) - props {:file-id file-id - :share-id nil}] + comment (-> (db/insert! conn :comment params) + (decode-row) + (add-owner profile))] ;; Update thread modified-at attribute and assoc the current ;; profile to the participant set. - (db/update! conn :comment-thread - {:modified-at request-at - :participants (-> (:participants thread #{}) - (conj profile-id) - (db/tjson)) - :mentions (-> (:mentions thread) - (set) - (into mentions) - (db/encode-pgarray conn "uuid"))} - {:id thread-id}) + (let [mentions (into (:mentions thread) mentions) + participants (-> (:participants thread #{}) + (conj profile-id)) + params {:modified-at request-at + :participants (db/tjson participants) + :mentions (db/encode-pgarray mentions conn "uuid")} - ;; Update the current profile status in relation to the - ;; current thread. + ;; Update the page-name cached attribute on comment thread table. + params (cond-> params + (not= (:page-name file) (:page-name thread)) + (assoc :page-name (:page-name file)))] + + (db/update! conn :comment-thread params + {:id thread-id} + {::db/return-keys false})) + + ;; Update the current profile status in relation to the current thread (upsert-comment-thread-status! conn profile-id thread-id) - (let [params {:project-id project-id - :profile-id profile-id - :team-id team-id - :file-id (:file-id thread) - :page-id (:page-id thread) - :file-name file-name - :page-name page-name}] - (send-comment-emails! conn params comment thread)) + (send-comment-emails! conn profile comment thread file) - (vary-meta comment assoc ::audit/props props)))) + (vary-meta comment assoc ::audit/props comment)))) ;; --- COMMAND: Update Comment @@ -645,16 +656,20 @@ [:id ::sm/uuid] [:content [:string {:max 250}]] [:share-id {:optional true} [:maybe ::sm/uuid]] - [:mentions {:optional true} [:vector ::sm/uuid]]]) + [:mentions {:optional true} [::sm/set ::sm/uuid]]]) + +;; TODO: Check if there are new mentions, if there are send the new emails. -;; TODO Check if there are new mentions, if there are send the new emails. (sv/defmethod ::update-comment {::doc/added "1.15" ::sm/params schema:update-comment ::db/transaction true} [{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id ::rpc/request-at id share-id content mentions]}] - (let [{:keys [thread-id owner-id] :as comment} (get-comment conn id ::sql/for-update true) - {:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true)] + (let [{:keys [thread-id owner-id] :as comment} + (get-comment conn id ::sql/for-update true) + + {:keys [file-id page-id] :as thread} + (get-comment-thread conn thread-id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) @@ -675,10 +690,10 @@ :page-name page-name :mentions (-> (:mentions thread) - (set) (into mentions) (db/encode-pgarray conn "uuid"))} - {:id thread-id}) + {:id thread-id} + {::db/return-keys false}) nil))) ;; --- COMMAND: Delete Comment Thread @@ -700,7 +715,8 @@ (ex/raise :type :validation :code :not-allowed)) - (db/delete! conn :comment-thread {:id id}) + (db/delete! conn :comment-thread {:id id} + {::db/return-keys false}) nil)) ;; --- COMMAND: Delete comment @@ -716,13 +732,19 @@ ::sm/params schema:delete-comment ::db/transaction true} [{:keys [::db/conn]} {:keys [::rpc/profile-id id share-id]}] - (let [{:keys [owner-id thread-id] :as comment} (get-comment conn id ::sql/for-update true) - {:keys [file-id] :as thread} (get-comment-thread conn thread-id)] + (let [{:keys [owner-id thread-id] :as comment} + (get-comment conn id ::sql/for-update true) + + {:keys [file-id]} + (get-comment-thread conn thread-id)] + (files/check-comment-permissions! conn profile-id file-id share-id) (when-not (= owner-id profile-id) (ex/raise :type :validation :code :not-allowed)) - (db/delete! conn :comment {:id id}) + + (db/delete! conn :comment {:id id} + {::db/return-keys false}) nil)) ;; --- COMMAND: Update comment thread position @@ -740,13 +762,14 @@ ::sm/params schema:update-comment-thread-position ::db/transaction true} [{:keys [::db/conn]} {:keys [::rpc/profile-id ::rpc/request-at id position frame-id share-id]}] - (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)] + (let [{:keys [file-id]} (get-comment-thread conn id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) (db/update! conn :comment-thread {:modified-at request-at :position (db/pgpoint position) :frame-id frame-id} - {:id (:id thread)}) + {:id id} + {::db/return-keys false}) nil)) ;; --- COMMAND: Update comment frame @@ -763,10 +786,11 @@ ::sm/params schema:update-comment-thread-frame ::db/transaction true} [{:keys [::db/conn]} {:keys [::rpc/profile-id ::rpc/request-at id frame-id share-id]}] - (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)] + (let [{:keys [file-id]} (get-comment-thread conn id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) (db/update! conn :comment-thread {:modified-at request-at :frame-id frame-id} - {:id id}) + {:id id} + {::db/return-keys false}) nil)) diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index a6c74b810..fe3b028d2 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -614,7 +614,8 @@ l.name, l.revn, l.vern, - l.synced_at + l.synced_at, + l.is_shared FROM libs AS l WHERE l.deleted_at IS NULL OR l.deleted_at > now();") diff --git a/backend/src/app/rpc/commands/viewer.clj b/backend/src/app/rpc/commands/viewer.clj index b258420ee..1eeb13818 100644 --- a/backend/src/app/rpc/commands/viewer.clj +++ b/backend/src/app/rpc/commands/viewer.clj @@ -70,6 +70,7 @@ :deleted-at nil})] {:users members + :profiles members :fonts fonts :project project :share-links links diff --git a/common/src/app/common/test_helpers/shapes.cljc b/common/src/app/common/test_helpers/shapes.cljc index 408e1233e..903f51f38 100644 --- a/common/src/app/common/test_helpers/shapes.cljc +++ b/common/src/app/common/test_helpers/shapes.cljc @@ -13,7 +13,6 @@ [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] [app.common.types.shape-tree :as ctst] @@ -43,25 +42,25 @@ frame-id (if (cfh/frame-shape? parent) (:id parent) (:frame-id parent))] - (ctf/update-file-data - file - (fn [file-data] - (ctpl/update-page file-data - (:id page) - #(ctst/add-shape (:id shape) - shape - % - frame-id - parent-id - nil - true)))))) + (update file :data + (fn [file-data] + (ctpl/update-page file-data + (:id page) + #(ctst/add-shape (:id shape) + shape + % + frame-id + parent-id + nil + true)))))) (defn get-shape [file label & {:keys [page-label]}] - (let [page (if page-label - (thf/get-page file page-label) - (thf/current-page file))] - (ctst/get-shape page (thi/id label)))) + (let [page (if page-label + (thf/get-page file page-label) + (thf/current-page file)) + shape-id (thi/id label)] + (ctst/get-shape page shape-id))) (defn get-shape-by-id [file id & {:keys [page-label]}] @@ -76,12 +75,11 @@ (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))))))) + (update file :data + (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}] @@ -104,7 +102,7 @@ (defn add-sample-library-color [file label & {:keys [] :as params}] (let [color (sample-color label params)] - (ctf/update-file-data file #(ctcl/add-color % color)))) + (update file :data ctcl/add-color color))) (defn sample-typography [label & {:keys [] :as params}] @@ -113,7 +111,7 @@ (defn add-sample-typography [file label & {:keys [] :as params}] (let [typography (sample-typography label params)] - (ctf/update-file-data file #(cttl/add-typography % typography)))) + (update file :data cttl/add-typography typography))) (defn add-interaction [file origin-label dest-label] @@ -124,9 +122,8 @@ (ctsi/set-destination (:id dest)) (assoc :position-relative-to (:id origin))) interactions (ctsi/add-interaction (:interactions origin) interaction)] - (ctf/update-file-data - file - (fn [file-data] - (ctpl/update-page file-data - (:id page) - #(ctst/set-shape % (assoc origin :interactions interactions))))))) + (update file :data + (fn [file-data] + (ctpl/update-page file-data + (:id page) + #(ctst/set-shape % (assoc origin :interactions interactions))))))) diff --git a/common/src/app/common/types/color.cljc b/common/src/app/common/types/color.cljc index ab50f4be0..3f309096b 100644 --- a/common/src/app/common/types/color.cljc +++ b/common/src/app/common/types/color.cljc @@ -143,6 +143,7 @@ ;; --- fill +;; FIXME: revisit, this generates invalid colors (defn fill->shape-color [fill] (d/without-nils @@ -153,6 +154,16 @@ :ref-id (:fill-color-ref-id fill) :ref-file (:fill-color-ref-file fill)})) +(defn fill->color + [fill] + (d/without-nils + {:color (:fill-color fill) + :opacity (:fill-opacity fill) + :gradient (:fill-color-gradient fill) + :image (:fill-image fill) + :id (:fill-color-ref-id fill) + :file-id (:fill-color-ref-file fill)})) + (defn set-fill-color [shape position color opacity gradient image] (update-in shape [:fills position] diff --git a/common/src/app/common/types/typography.cljc b/common/src/app/common/types/typography.cljc index 4263bd844..74f66b4e3 100644 --- a/common/src/app/common/types/typography.cljc +++ b/common/src/app/common/types/typography.cljc @@ -103,4 +103,3 @@ (txt/transform-nodes #(not= (:typography-ref-file %) file-id) remove-ref-file content))))) - diff --git a/frontend/src/app/main/data/changes.cljs b/frontend/src/app/main/data/changes.cljs index 341357e98..72de74ea9 100644 --- a/frontend/src/app/main/data/changes.cljs +++ b/frontend/src/app/main/data/changes.cljs @@ -12,6 +12,7 @@ [app.common.logging :as log] [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] + [app.main.data.helpers :as dsh] [app.main.features :as features] [app.main.worker :as uw] [app.util.time :as dt] @@ -76,32 +77,30 @@ (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]) + (let [undo-changes + (if pending + (->> pending + (map :undo-changes) + (reverse) + (mapcat identity) + (vec)) + nil) - 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) - 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)))))))) + apply-changes + (fn [fdata] + (let [fdata (cpc/process-changes fdata undo-changes false) + fdata (cpc/process-changes fdata redo-changes false) + pids (into #{} xf:map-page-id redo-changes)] + (reduce #(ctst/update-object-indices %1 %2) fdata pids)))] + (update-in state [:files file-id :data] apply-changes))))) (defn commit "Create a commit event instance" @@ -156,17 +155,11 @@ (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])))) + (:revn (dsh/lookup-file state file-id))) (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])))) + (:vern (dsh/lookup-file state file-id))) (defn commit-changes "Schedules a list of changes to execute now, and add the corresponding undo changes to diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs index 73d8a4c0f..fd818b9a7 100644 --- a/frontend/src/app/main/data/comments.cljs +++ b/frontend/src/app/main/data/comments.cljs @@ -13,7 +13,8 @@ [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] [app.main.data.event :as ev] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] + [app.main.data.team :as dtm] [app.main.repo :as rp] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -25,8 +26,10 @@ [:file-id ::sm/uuid] [:project-id ::sm/uuid] [:owner-id ::sm/uuid] - [:page-name {:optional true} :string] - [:file-name :string] + [:owner-fullname {:optional true} ::sm/text] + [:owner-email {:optional true} ::sm/email] + [:page-name {:optional true} ::sm/text] + [:file-name ::sm/text] [:seqn :int] [:content :string] [:participants ::sm/set-of-uuid] @@ -40,7 +43,10 @@ [:map {:title "Comment"} [:id ::sm/uuid] [:thread-id ::sm/uuid] + [:file-id ::sm/uuid] [:owner-id ::sm/uuid] + [:owner-fullname {:optional true} ::sm/text] + [:owner-email {:optional true} ::sm/email] [:created-at ::sm/inst] [:modified-at ::sm/inst] [:content :string]]) @@ -75,10 +81,11 @@ (ptk/reify ::created-thread-on-workspace ptk/UpdateEvent (update [_ state] - (let [position (select-keys thread [:position :frame-id])] + (let [position (select-keys thread [:position :frame-id]) + page-id (or page-id (:current-page-id state))] (-> state (update :comment-threads assoc id (dissoc thread :comment)) - (update-in [:workspace-data :pages-index page-id :comment-thread-positions] assoc id position) + (dsh/update-page page-id #(update % :comment-thread-positions assoc id position)) (cond-> open? (update :comments-local assoc :open id)) (update :comments-local assoc :options nil) @@ -94,8 +101,6 @@ :id id :content-size (count (:content comment))})))))) - - (def ^:private schema:create-thread-on-workspace [:map {:title "created-thread-on-workspace"} @@ -114,7 +119,7 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) frame-id (ctst/get-frame-id-by-position objects (:position params)) params (-> params (update-mentions) @@ -263,7 +268,7 @@ (rx/of (refresh-comment-thread thread))))))) (defn update-comment - [{:keys [id content thread-id] :as comment}] + [{:keys [id content thread-id file-id] :as comment}] (dm/assert! "expected valid comment" (check-comment! comment)) @@ -277,15 +282,13 @@ ptk/UpdateEvent (update [_ state] - (-> state - (d/update-in-when [:comments thread-id id] assoc :content content))) + (d/update-in-when state [:comments thread-id id] assoc :content content)) ptk/WatchEvent (watch [_ state _] - (let [file-id (:current-file-id state) - share-id (-> state :viewer-local :share-id) - params (-> {:id id :content content :share-id share-id} - (update-mentions))] + (let [share-id (-> state :viewer-local :share-id) + params {:id id :content content :share-id share-id} + params (update-mentions params)] (->> (rp/cmd! :update-comment params) (rx/catch #(rx/throw {:type :comment-error})) (rx/map #(retrieve-comment-threads file-id))))))) @@ -299,11 +302,10 @@ (ptk/reify ::delete-comment-thread-on-workspace ptk/UpdateEvent (update [_ state] - (let [page-id (:current-page-id state)] - (-> state - (update-in [:workspace-data :pages-index page-id :comment-thread-positions] dissoc id) - (update :comments dissoc id) - (update :comment-threads dissoc id)))) + (-> state + (dsh/update-page #(update % :comment-thread-positions dissoc id)) + (update :comments dissoc id) + (update :comment-threads dissoc id))) ptk/WatchEvent (watch [_ _ _] @@ -380,35 +382,37 @@ (rx/map #(partial fetched %)) (rx/catch #(rx/throw {:type :comment-error})))))))) + +(defn- comment-threads-fetched + [threads] + (ptk/reify ::comment-threads-fetched + ptk/UpdateEvent + (update [_ state] + (reduce (fn [state {:keys [id file-id page-id] :as thread}] + (-> state + (update :comment-threads assoc id thread) + (dsh/update-page file-id page-id + (fn [page] + (update-in page [:comment-thread-positions id] + (fn [state] + (-> state + (assoc :position (:position thread)) + (assoc :frame-id (:frame-id thread))))))))) + state + threads)))) + (defn retrieve-comment-threads [file-id] - (dm/assert! (uuid? file-id)) - (letfn [(set-comment-threds [state comment-thread] - (let [path [:workspace-data :pages-index (:page-id comment-thread) :comment-thread-positions (:id comment-thread)] - thread-position (get-in state path)] - (cond-> state - (nil? thread-position) - (-> - (assoc-in (conj path :position) (:position comment-thread)) - (assoc-in (conj path :frame-id) (:frame-id comment-thread)))))) - (fetched [[users comments] state] - (let [pages (-> (get-in state [:workspace-data :pages]) - set) - comments (filter #(contains? pages (:page-id %)) comments) - state (-> state - (assoc :comment-threads (d/index-by :id comments)) - (update :current-file-comments-users merge (d/index-by :id users)))] - (reduce set-comment-threds state comments)))] + (ptk/reify ::retrieve-comment-threads + ptk/WatchEvent + (watch [_ state _] + (let [share-id (-> state :viewer-local :share-id)] + (rx/merge + (->> (rp/cmd! :get-comment-threads {:file-id file-id :share-id share-id}) + (rx/map comment-threads-fetched)) - (ptk/reify ::retrieve-comment-threads - ptk/WatchEvent - (watch [_ state _] - (let [share-id (-> state :viewer-local :share-id)] - (->> (rx/zip (rp/cmd! :get-team-users {:file-id file-id}) - (rp/cmd! :get-comment-threads {:file-id file-id :share-id share-id})) - (rx/take 1) - (rx/map #(partial fetched %)) - (rx/catch #(rx/throw {:type :comment-error})))))))) + ;; Refresh team members + (rx/of (dtm/fetch-members))))))) (defn retrieve-comments [thread-id] @@ -423,6 +427,8 @@ (rx/map #(partial fetched %)) (rx/catch #(rx/throw {:type :comment-error})))))))) + +;; FIXME: revisit (defn retrieve-unread-comment-threads "A event used mainly in dashboard for retrieve all unread threads of a team." [team-id] @@ -544,6 +550,13 @@ ;; Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defn get-owner + [thread-or-comment] + {:id (:owner-id thread-or-comment) + :fullname (:owner-fullname thread-or-comment) + :email (:owner-email thread-or-comment) + :photo-id (:owner-photo-id thread-or-comment)}) + (defn group-threads-by-page [threads] (letfn [(group-by-page [result thread] @@ -621,7 +634,7 @@ (ptk/reify ::detach-comment-thread ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) is-frame? (fn [id] (= :frame (get-in objects [id :type]))) frame-ids? (into #{} (filter is-frame?) ids)] @@ -635,7 +648,7 @@ (defn fetch-profiles "Fetch or refresh all profile data for comments of the current file" [] - (ptk/reify ::fetch-comments-profiles + (ptk/reify ::fetch-profiles ptk/WatchEvent (watch [_ state _] (let [file-id (:current-file-id state) diff --git a/frontend/src/app/main/data/common.cljs b/frontend/src/app/main/data/common.cljs index 0036824b1..7b833e896 100644 --- a/frontend/src/app/main/data/common.cljs +++ b/frontend/src/app/main/data/common.cljs @@ -12,6 +12,7 @@ [app.common.schema :as sm] [app.common.types.components-list :as ctkl] [app.common.types.team :as ctt] + [app.main.data.helpers :as dsh] [app.main.data.modal :as modal] [app.main.data.notifications :as ntf] [app.main.data.persistence :as-alias dps] @@ -111,8 +112,9 @@ ptk/WatchEvent (watch [_ state _] (let [features (features/get-team-enabled-features state) - data (:workspace-data state) - file (:workspace-file state)] + file (dsh/lookup-file state) + data (get file :data)] + (->> (if (and data file) (rx/of {:name (:name file) :components-count (count (ctkl/components-seq data)) @@ -368,7 +370,9 @@ (let [team-id (or team-id (:current-team-id state)) file-id (or file-id (:current-file-id state)) page-id (or page-id (:current-page-id state) - (dm/get-in state [:workspace-data :pages 0])) + (-> (dsh/lookup-file-data state file-id) + (get :pages) + (first))) params (-> (rt/get-params state) (assoc :team-id team-id) diff --git a/frontend/src/app/main/data/exports/assets.cljs b/frontend/src/app/main/data/exports/assets.cljs index ca1d41183..1e800aee6 100644 --- a/frontend/src/app/main/data/exports/assets.cljs +++ b/frontend/src/app/main/data/exports/assets.cljs @@ -8,9 +8,9 @@ (:require [app.common.uuid :as uuid] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.modal :as modal] [app.main.data.persistence :as dwp] - [app.main.data.workspace.state-helpers :as wsh] [app.main.refs :as refs] [app.main.repo :as rp] [app.main.store :as st] @@ -56,11 +56,11 @@ (watch [_ state _] (let [file-id (:current-file-id state) page-id (:current-page-id state) - selected (or selected (wsh/lookup-selected state page-id {})) + selected (or selected (dsh/lookup-selected state page-id {})) shapes (if (seq selected) - (wsh/lookup-shapes state selected) - (reverse (wsh/filter-shapes state #(pos? (count (:exports %)))))) + (dsh/lookup-shapes state selected) + (reverse (dsh/filter-shapes state #(pos? (count (:exports %)))))) exports (for [shape shapes export (:exports shape)] diff --git a/frontend/src/app/main/data/fonts.cljs b/frontend/src/app/main/data/fonts.cljs index e8503ea59..a1aba3d67 100644 --- a/frontend/src/app/main/data/fonts.cljs +++ b/frontend/src/app/main/data/fonts.cljs @@ -327,27 +327,23 @@ ;; Workspace related events ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defn- update-recent-font + "Moves the font/font to the top of the list of recents and then truncates up to 4" + [state file-id font] + (let [xform (comp + (remove #(= font %)) + (take 3))] + (update state file-id #(into [font] xform %)))) + (defn add-recent-font [font] (ptk/reify ::add-recent-font ptk/UpdateEvent (update [_ state] - (let [recent-fonts (get-in state [:workspace-data :recent-fonts]) - most-recent-fonts (into [font] (comp (remove #(= font %)) (take 3)) recent-fonts)] - (assoc-in state [:workspace-data :recent-fonts] most-recent-fonts))) + (let [file-id (:current-file-id state)] + (update state :recent-fonts update-recent-font file-id font))) + ptk/EffectEvent (effect [_ state _] - (let [most-recent-fonts (get-in state [:workspace-data :recent-fonts])] - ;; FIXME: this should be prefixed by team - (swap! storage/user assoc ::recent-fonts most-recent-fonts))))) - -(defn load-recent-fonts - [fonts] - (ptk/reify ::load-recent-fonts - ptk/UpdateEvent - (update [_ state] - (let [fonts-map (d/index-by :id fonts) - saved-recent-fonts (->> (::recent-fonts storage/user) - (keep #(get fonts-map (:id %))) - (into #{}))] - (assoc-in state [:workspace-data :recent-fonts] saved-recent-fonts))))) + (let [recent-fonts (:recent-fonts state)] + (swap! storage/user assoc :recent-fonts recent-fonts))))) diff --git a/frontend/src/app/main/data/helpers.cljs b/frontend/src/app/main/data/helpers.cljs new file mode 100644 index 000000000..b104af0dc --- /dev/null +++ b/frontend/src/app/main/data/helpers.cljs @@ -0,0 +1,170 @@ +;; 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.helpers + (:require + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.common.files.helpers :as cfh] + [app.common.geom.point :as gpt] + [app.common.geom.shapes :as gsh] + [app.common.svg.path.command :as upc])) + +(defn lookup-profile + ([state] + (:profile state)) + ([state profile-id] + (dm/get-in state [:profiles profile-id]))) + +(defn lookup-libraries + "Retrieve all libraries, including the local file." + [state] + (:files state)) + +(defn lookup-file + ([state] + (lookup-file state (:current-file-id state))) + ([state file-id] + (dm/get-in state [:files file-id]))) + +(defn lookup-file-data + ([state] + (lookup-file-data state (:current-file-id state))) + ([state file-id] + (dm/get-in state [:files file-id :data]))) + +(defn get-page + [fdata page-id] + (dm/get-in fdata [:pages-index page-id])) + +(defn lookup-page + ([state] + (let [file-id (:current-file-id state) + page-id (:current-page-id state)] + (lookup-page state file-id page-id))) + ([state page-id] + (let [file-id (:current-file-id state)] + (lookup-page state file-id page-id))) + ([state file-id page-id] + (dm/get-in state [:files file-id :data :pages-index page-id]))) + +(defn lookup-page-objects + ([state] + (lookup-page-objects state + (:current-file-id state) + (:current-page-id state))) + ([state page-id] + (lookup-page-objects state + (:current-file-id state) + page-id)) + ([state file-id page-id] + (-> (lookup-page state file-id page-id) + (get :objects)))) + +(defn process-selected-shapes + ([objects selected] + (process-selected-shapes objects selected nil)) + + ([objects selected {:keys [omit-blocked?] :or {omit-blocked? false}}] + (letfn [(selectable? [id] + (and (contains? objects id) + (or (not omit-blocked?) + (not (get-in objects [id :blocked] false)))))] + (let [selected (->> selected (cfh/clean-loops objects))] + (into (d/ordered-set) + (filter selectable?) + selected))))) + +;; DEPRECATED +(defn lookup-selected-raw + [state] + (dm/get-in state [:workspace-local :selected])) + +(defn get-selected-ids + [state] + (dm/get-in state [:workspace-local :selected])) + +(defn lookup-selected + ([state] + (lookup-selected state (:current-page-id state) nil)) + ([state options] + (lookup-selected state (:current-page-id state) options)) + ([state page-id options] + (let [objects (lookup-page-objects state page-id) + selected (dm/get-in state [:workspace-local :selected])] + (process-selected-shapes objects selected options)))) + +(defn lookup-shape + ([state id] + (lookup-shape state (:current-page-id state) id)) + + ([state page-id id] + (let [objects (lookup-page-objects state page-id)] + (get objects id)))) + +(defn lookup-shapes + ([state ids] + (lookup-shapes state (:current-page-id state) ids)) + ([state page-id ids] + (let [objects (lookup-page-objects state page-id)] + (into [] (keep (d/getf objects)) ids)))) + +(defn update-file + ([state f] + (update-file state (:current-file-id state) f)) + ([state file-id f] + (d/update-in-when state [:files file-id] f))) + +(defn update-page + ([state f] + (update-page state + (:current-file-id state) + (:current-page-id state) + f)) + ([state page-id f] + (update-page state + (:current-file-id state) + page-id + f)) + ([state file-id page-id f] + (d/update-in-when state [:files file-id :data :pages-index page-id] f))) + +(defn filter-shapes + ([state filter-fn] + (filter-shapes state (:current-page-id state) filter-fn)) + ([state page-id filter-fn] + (let [objects (lookup-page-objects state page-id)] + (into [] (filter filter-fn) (vals objects))))) + +(defn select-bool-children + [state parent-id] + (let [objects (lookup-page-objects state) + + shape-modifiers + (:workspace-modifiers state) + + content-modifiers + (dm/get-in state [:workspace-local :edit-path])] + + (reduce (fn [result id] + (if-let [shape (get objects id)] + (let [modifiers (dm/get-in shape-modifiers [id :modifiers]) + shape (if (some? modifiers) + (gsh/transform-shape shape modifiers) + shape) + modifiers (dm/get-in content-modifiers [id :content-modifiers]) + shape (if (some? modifiers) + (update shape :content upc/apply-content-modifiers modifiers) + shape)] + (assoc result id shape)) + result)) + {} + (cfh/get-children-ids objects parent-id)))) + +(defn get-viewport-center + [state] + (when-let [{:keys [x y width height]} (get-in state [:workspace-local :vbox])] + (gpt/point (+ x (/ width 2)) (+ y (/ height 2))))) diff --git a/frontend/src/app/main/data/persistence.cljs b/frontend/src/app/main/data/persistence.cljs index 759bc0fb9..727bb8548 100644 --- a/frontend/src/app/main/data/persistence.cljs +++ b/frontend/src/app/main/data/persistence.cljs @@ -11,6 +11,7 @@ [app.common.logging :as log] [app.common.uuid :as uuid] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.repo :as rp] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -49,11 +50,7 @@ ptk/UpdateEvent (update [_ state] (log/dbg :hint "update-file-revn" :file-id (dm/str file-id) :revn revn) - (if-let [current-file-id (:current-file-id state)] - (if (= file-id current-file-id) - (update-in state [:workspace-file :revn] max revn) - (d/update-in-when state [:libraries file-id :revn] max revn)) - state)) + (dsh/update-file state file-id #(update % :revn max revn))) ptk/EffectEvent (effect [_ _ _] diff --git a/frontend/src/app/main/data/preview.cljs b/frontend/src/app/main/data/preview.cljs index e5865e19a..7be41d6e2 100644 --- a/frontend/src/app/main/data/preview.cljs +++ b/frontend/src/app/main/data/preview.cljs @@ -10,7 +10,7 @@ [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.types.shape-tree :as ctst] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [app.main.fonts :as fonts] [app.main.refs :as refs] [app.util.code-beautify :as cb] @@ -57,7 +57,7 @@ (ptk/reify ::update-preview ptk/EffectEvent (effect [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects shape-id) all-children @@ -94,7 +94,7 @@ (ptk/reify ::open-preview-selected ptk/WatchEvent (watch [_ state _] - (let [shape-id (first (wsh/lookup-selected state)) + (let [shape-id (first (dsh/lookup-selected state)) closed-preview (rx/subject) preview (.open js/window "/#/frame-preview") listener-fn #(rx/push! closed-preview true)] diff --git a/frontend/src/app/main/data/profile.cljs b/frontend/src/app/main/data/profile.cljs index 2a22ad57e..1427e2317 100644 --- a/frontend/src/app/main/data/profile.cljs +++ b/frontend/src/app/main/data/profile.cljs @@ -330,19 +330,6 @@ (rx/map (constantly (refresh-profile))) (rx/catch on-error)))))) -(defn fetch-users - [] - (letfn [(fetched [users state] - (->> users - (d/index-by :id) - (assoc state :users)))] - (ptk/reify ::fetch-team-users - ptk/WatchEvent - (watch [_ state _] - (let [team-id (:current-team-id state)] - (->> (rp/cmd! :get-team-users {:team-id team-id}) - (rx/map #(partial fetched %)))))))) - (defn fetch-file-comments-users [{:keys [team-id]}] (dm/assert! (uuid? team-id)) diff --git a/frontend/src/app/main/data/tokens.cljs b/frontend/src/app/main/data/tokens.cljs index e70f557bf..7c873ccef 100644 --- a/frontend/src/app/main/data/tokens.cljs +++ b/frontend/src/app/main/data/tokens.cljs @@ -13,8 +13,8 @@ [app.common.types.shape :as cts] [app.common.types.tokens-lib :as ctob] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.workspace.shapes :as dwsh] - [app.main.refs :as refs] [app.main.ui.workspace.tokens.token-set :as wtts] [app.main.ui.workspace.tokens.update :as wtu] [beicon.v2.core :as rx] @@ -42,18 +42,15 @@ ;; TOKENS Getters ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn get-tokens-lib [state] - (get-in state [:workspace-data :tokens-lib])) +(defn get-tokens-lib + [state] + (-> (dsh/lookup-file-data state) + (get :tokens-lib))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; TOKENS Actions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn get-token-data-from-token-id - [id] - (let [workspace-data (deref refs/workspace-data)] - (get (:tokens workspace-data) id))) - (defn set-selected-token-set-path [full-path] (ptk/reify ::set-selected-token-set-path @@ -112,7 +109,8 @@ (ptk/reify ::delete-token-theme ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) + changes (-> (pcb/empty-changes it) (pcb/with-library-data data) (pcb/delete-token-theme group name))] @@ -178,7 +176,7 @@ (ptk/reify ::import-tokens-lib ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) update-token-set-change (some-> lib (ctob/get-sets) (first) @@ -196,7 +194,7 @@ (ptk/reify ::delete-token-set-path ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) changes (-> (pcb/empty-changes it) (pcb/with-library-data data) (pcb/delete-token-set-path prefixed-full-set-path))] @@ -259,7 +257,7 @@ (ptk/reify ::delete-token ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) changes (-> (pcb/empty-changes it) (pcb/with-library-data data) (pcb/delete-token set-name token-name))] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index a72e8a616..8eaab9828 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -40,6 +40,7 @@ [app.main.data.common :as dcm] [app.main.data.event :as ev] [app.main.data.fonts :as df] + [app.main.data.helpers :as dsh] [app.main.data.modal :as modal] [app.main.data.notifications :as ntf] [app.main.data.plugins :as dp] @@ -67,7 +68,6 @@ [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.texts :as dwtxt] [app.main.data.workspace.thumbnails :as dwth] [app.main.data.workspace.transforms :as dwt] @@ -174,16 +174,21 @@ (ptk/reify ::libraries-fetched ptk/UpdateEvent (update [_ state] - (assoc state :libraries (d/index-by :id libraries))) + (let [libraries (d/index-by :id libraries)] + (update state :files merge libraries))) ptk/WatchEvent (watch [_ state _] - (let [file-id (dm/get-in state [:workspace-file :id]) - ignore-until (dm/get-in state [:workspace-file :ignore-sync-until]) - needs-check? (some #(and (> (:modified-at %) (:synced-at %)) - (or (not ignore-until) - (> (:modified-at %) ignore-until))) - libraries)] + (let [file (dsh/lookup-file state) + file-id (get file :id) + ignore-until (get file :ignore-sync-until) + + needs-check? + (some #(and (> (:modified-at %) (:synced-at %)) + (or (not ignore-until) + (> (:modified-at %) ignore-until))) + libraries)] + (when needs-check? (rx/concat (rx/timer 1000) (rx/of (dwl/notify-sync-file file-id)))))))) @@ -213,23 +218,19 @@ (rx/map dwl/library-thumbnails-fetched)))))))))) (defn- workspace-initialized - [] + [file-id] (ptk/reify ::workspace-initialized ptk/UpdateEvent (update [_ state] (-> state (assoc :workspace-undo {}) - (assoc :workspace-ready true))) + (assoc :workspace-ready file-id))) ptk/WatchEvent - (watch [_ state _] - (rx/of - (when (and (not (boolean (-> state :profile :props :v2-info-shown))) - (features/active-feature? state "components/v2")) - (modal/show :v2-info {})) - (dp/check-open-plugin) - (fdf/fix-deleted-fonts) - (fbs/fix-broken-shapes))))) + (watch [_ _ _] + (rx/of (dp/check-open-plugin) + (fdf/fix-deleted-fonts) + (fbs/fix-broken-shapes))))) (defn- bundle-fetched [{:keys [features file thumbnails]}] @@ -242,10 +243,10 @@ ptk/UpdateEvent (update [_ state] - (-> state - (assoc :thumbnails thumbnails) - (assoc :workspace-file (dissoc file :data)) - (assoc :workspace-data (:data file)))) + (let [file-id (:id file)] + (-> state + (assoc :thumbnails thumbnails) + (update :files assoc file-id file)))) ptk/WatchEvent (watch [_ state _] @@ -317,11 +318,13 @@ (ptk/reify ::initialize-workspace ptk/UpdateEvent (update [_ state] - (assoc state - :recent-colors (:recent-colors storage/user) - :workspace-ready false - :current-file-id file-id - :workspace-presence {})) + (-> state + (dissoc :files) + (dissoc :workspace-ready) + (assoc :recent-colors (:recent-colors storage/user)) + (assoc :recent-fonts (:recent-fonts storage/user)) + (assoc :current-file-id file-id) + (assoc :workspace-presence {}))) ptk/WatchEvent (watch [_ state stream] @@ -341,7 +344,7 @@ (rx/map deref) (rx/mapcat (fn [{:keys [file]}] (rx/of (dpj/initialize-project (:project-id file)) - (-> (workspace-initialized) + (-> (workspace-initialized file-id) (with-meta {:file-id file-id})))))) (when-let [component-id (some-> rparams :component-id parse-uuid)] @@ -388,12 +391,11 @@ ptk/UpdateEvent (update [_ state] (-> state + ;; FIXME: revisit (dissoc :current-file-id - :workspace-data :workspace-editor-state - :workspace-file - :libraries + :files :workspace-media-objects :workspace-persistence :workspace-presence @@ -431,7 +433,7 @@ (ptk/reify ::initialize-page ptk/UpdateEvent (update [_ state] - (if-let [{:keys [id] :as page} (dm/get-in state [:workspace-data :pages-index page-id])] + (if-let [{:keys [id] :as page} (dsh/lookup-page state page-id)] ;; we maintain a cache of page state for user convenience with the exception of the ;; selection; when user abandon the current page, the selection is lost (let [local (dm/get-in state [:workspace-cache id] default-workspace-local)] @@ -483,7 +485,7 @@ (cond (some? metadata) (cf/resolve-file-media metadata) (some? fill-image) (cf/resolve-file-media fill-image))))) - uris (into #{} xform (wsh/lookup-page-objects state page-id))] + uris (into #{} xform (dsh/lookup-page-objects state page-id))] (->> (rx/from uris) (rx/subs! #(http/fetch-data-uri % false))))))) @@ -503,7 +505,9 @@ ptk/WatchEvent (watch [it state _] - (let [pages (get-in state [:workspace-data :pages-index]) + (let [pages (-> (dsh/lookup-file-data state) + (get :pages-index)) + unames (cfh/get-used-names pages) name (cfh/generate-unique-name unames "Page 1") @@ -518,14 +522,14 @@ ptk/WatchEvent (watch [it state _] (let [id (uuid/next) - pages (get-in state [:workspace-data :pages-index]) + fdata (dsh/lookup-file-data state) + pages (get fdata :pages-index) + page (get pages page-id) + unames (cfh/get-used-names pages) - page (get-in state [:workspace-data :pages-index page-id]) name (cfh/generate-unique-name unames (:name page)) - fdata (:workspace-data state) - components-v2 (dm/get-in fdata [:options :components-v2]) - objects (->> (:objects page) - (d/mapm (fn [_ val] (dissoc val :use-for-thumbnail)))) + objects (update-vals (:objects page) #(dissoc % :use-for-thumbnail)) + main-instances-ids (set (keep #(when (ctk/main-instance? (val %)) (key %)) objects)) ids-to-remove (set (apply concat (map #(cfh/get-children-ids objects %) main-instances-ids))) @@ -537,7 +541,7 @@ component fdata (gpt/point (:x shape) (:y shape)) - components-v2 + true {:keep-ids? true}) children (into {} (map (fn [shape] [(:id shape) shape]) new-shapes)) objs (assoc objs id new-shape)] @@ -576,10 +580,9 @@ (ptk/reify ::rename-page ptk/WatchEvent (watch [it state _] - (let [page (get-in state [:workspace-data :pages-index id]) + (let [page (dsh/lookup-page state id) changes (-> (pcb/empty-changes it) (pcb/mod-page page {:name name}))] - (rx/of (dch/commit-changes changes)))))) (defn set-plugin-data @@ -599,20 +602,14 @@ (ptk/reify ::set-file-plugin-data ptk/WatchEvent (watch [it state _] - (let [file-data - (if (= file-id (:current-file-id state)) - (:workspace-data state) - (get-in state [:libraries file-id :data])) - - changes - (-> (pcb/empty-changes it) - (pcb/with-file-data file-data) - (assoc :file-id file-id) - (pcb/set-plugin-data type id page-id namespace key value))] + (let [file-data (dm/get-in state [:files file-id :data]) + changes (-> (pcb/empty-changes it) + (pcb/with-file-data file-data) + (assoc :file-id file-id) + (pcb/set-plugin-data type id page-id namespace key value))] (rx/of (dch/commit-changes changes))))))) (declare purge-page) -(declare go-to-file) (defn- delete-page-components [changes page] @@ -633,30 +630,29 @@ (ptk/reify ::delete-page ptk/WatchEvent (watch [it state _] - (let [components-v2 (features/active-feature? state "components/v2") - file-id (:current-file-id state) - file (wsh/get-file state file-id) - pages (get-in state [:workspace-data :pages]) - index (d/index-of pages id) - page (get-in state [:workspace-data :pages-index id]) - page (assoc page :index index) + (let [file-id (:current-file-id state) + fdata (dsh/lookup-file-data state file-id) + pindex (:pages-index fdata) + pages (:pages fdata) - changes (cond-> (pcb/empty-changes it) - components-v2 - (pcb/with-library-data file) - components-v2 - (delete-page-components page) - :always - (pcb/del-page page))] + index (d/index-of pages id) + page (get pindex id) + page (assoc page :index index) + + changes (-> (pcb/empty-changes it) + (pcb/with-library-data fdata) + (delete-page-components page) + (pcb/del-page page))] (rx/of (dch/commit-changes changes) (when (= id (:current-page-id state)) - (go-to-file))))))) + (dcm/go-to-workspace))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; WORKSPACE File Actions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; FIXME: move to common (defn rename-file [id name] {:pre [(uuid? id) (string? name)]} @@ -668,7 +664,8 @@ ptk/UpdateEvent (update [_ state] - (assoc-in state [:workspace-file :name] name)) + (let [file-id (:current-file-id state)] + (assoc-in state [:files file-id :name] name))) ptk/WatchEvent (watch [_ _ _] @@ -752,7 +749,7 @@ ptk/WatchEvent (watch [_ state _] (when-let [shape-id (d/nilv shape-id (dm/get-in state [:workspace-local :shape-for-rename]))] - (let [shape (wsh/lookup-shape state shape-id) + (let [shape (dsh/lookup-shape state shape-id) name (str/trim name) clean-name (cfh/clean-path name) valid? (and (not (str/ends-with? name "/")) @@ -782,7 +779,7 @@ (ptk/reify ::update-selected-shapes ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (rx/from (map #(update-shape % attrs) selected)))))) ;; --- Delete Selected @@ -793,7 +790,7 @@ (ptk/reify ::delete-selected ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) + (let [selected (dsh/lookup-selected state) hover-guides (get-in state [:workspace-guides :hover])] (cond (d/not-empty? selected) @@ -812,7 +809,7 @@ (ptk/reify ::start-rename-selected ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) + (let [selected (dsh/lookup-selected state) id (first selected)] (when (= (count selected) 1) (rx/of (dcm/go-to-workspace :layout :layers) @@ -832,8 +829,8 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected-ids (wsh/lookup-selected state) + objects (dsh/lookup-page-objects state page-id) + selected-ids (dsh/lookup-selected state) selected-shapes (map (d/getf objects) selected-ids) undo-id (js/Symbol) @@ -876,7 +873,7 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) ;; Ignore any shape whose parent is also intended to be moved ids (cfh/clean-loops objects ids) @@ -906,7 +903,7 @@ (ptk/reify ::relocate-selected-shapes ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (rx/of (relocate-shapes selected parent-id to-index)))))) (defn start-editing-selected @@ -914,8 +911,8 @@ (ptk/reify ::start-editing-selected ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) - objects (wsh/lookup-page-objects state)] + (let [selected (dsh/lookup-selected state) + objects (dsh/lookup-page-objects state)] (if (> (count selected) 1) (let [shapes-to-select @@ -950,8 +947,8 @@ (ptk/reify ::select-parent-layer ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) - objects (wsh/lookup-page-objects state) + (let [selected (dsh/lookup-selected state) + objects (dsh/lookup-page-objects state) shapes-to-select (->> selected (reduce @@ -970,7 +967,8 @@ (ptk/reify ::relocate-page ptk/WatchEvent (watch [it state _] - (let [prev-index (-> (get-in state [:workspace-data :pages]) + (let [prev-index (-> (dsh/lookup-file-data state) + (get :pages) (d/index-of id)) changes (-> (pcb/empty-changes it) (pcb/move-page id index prev-index))] @@ -1009,8 +1007,8 @@ (ptk/reify ::align-objects ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (or selected (wsh/lookup-selected state)) + (let [objects (dsh/lookup-page-objects state) + selected (or selected (dsh/lookup-selected state)) moved (if (= 1 (count selected)) (align-object-to-parent objects (first selected) axis) (align-objects-list objects selected axis)) @@ -1039,8 +1037,8 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (or ids (wsh/lookup-selected state)) + objects (dsh/lookup-page-objects state page-id) + selected (or ids (dsh/lookup-selected state)) moved (-> (map #(get objects %) selected) (gal/distribute-space axis)) undo-id (js/Symbol)] @@ -1070,8 +1068,8 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (wsh/lookup-selected state) + objects (dsh/lookup-page-objects state page-id) + selected (dsh/lookup-selected state) selected-obj (-> (map #(get objects %) selected)) multi (attrs/get-attrs-multi selected-obj [:proportion-lock]) multi? (= :multiple (:proportion-lock multi))] @@ -1157,9 +1155,12 @@ (ptk/reify ::show-component-in-assets ptk/WatchEvent (watch [_ state _] - (let [component-path (cfh/split-path (get-in state [:workspace-data :components component-id :path])) - paths (map (fn [i] (cfh/join-path (take (inc i) component-path))) (range (count component-path))) - file-id (:current-file-id state)] + (let [file-id (:current-file-id state) + fdata (dsh/lookup-file-data state file-id) + cpath (dm/get-in fdata [:components component-id :path]) + cpath (cfh/split-path cpath) + paths (map (fn [i] (cfh/join-path (take (inc i) cpath))) + (range (count cpath)))] (rx/concat (rx/from (map #(set-assets-group-open file-id :components % true) paths)) (rx/of (dcm/go-to-workspace :layout :assets) @@ -1189,8 +1190,8 @@ (ptk/reify ::show-shape-context-menu ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) - objects (wsh/lookup-page-objects state) + (let [selected (dsh/lookup-selected state) + objects (dsh/lookup-page-objects state) all-selected (into [] (mapcat #(cfh/get-children-with-self objects %)) selected) head (get objects (first selected)) @@ -1236,7 +1237,7 @@ (ptk/reify ::show-grid-cell-context-menu ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) grid (get objects grid-id) cells (->> (get-in state [:workspace-grid-edition grid-id :selected]) (map #(get-in grid [:layout-grid-cells %])))] @@ -1260,8 +1261,8 @@ (defn copy-selected [] (letfn [(sort-selected [state data] - (let [selected (wsh/lookup-selected state) - objects (wsh/lookup-page-objects state) + (let [selected (dsh/lookup-selected state) + objects (dsh/lookup-page-objects state) ;; Narrow the objects map so it contains only relevant data for ;; selected and its parents @@ -1325,9 +1326,10 @@ ;; When copying an instance that is nested inside another one, we need to ;; advance the shape refs to one or more levels of remote mains. (advance-copies [state selected data] - (let [file (wsh/get-local-file-full state) - libraries (wsh/get-libraries state) - page (wsh/lookup-page state) + (let [file (dsh/lookup-file state) + libraries (:files state) + ;; FIXME + page (dsh/lookup-page state) heads (mapcat #(ctn/get-child-heads (:objects data) %) selected)] (update data :objects #(reduce (partial advance-copy file libraries page) @@ -1364,15 +1366,16 @@ (catch :default e (on-copy-error e))) - (let [objects (wsh/lookup-page-objects state) - selected (->> (wsh/lookup-selected state) + (let [objects (dsh/lookup-page-objects state) + selected (->> (dsh/lookup-selected state) (cfh/clean-loops objects)) features (-> (features/get-team-enabled-features state) (set/difference cfeat/frontend-only-features)) file-id (:current-file-id state) frame-id (cfh/common-parent-frame objects selected) - version (dm/get-in state [:workspace-file :version]) + file (dsh/lookup-file state file-id) + version (get file :version) initial {:type :copied-shapes :features features @@ -1478,7 +1481,7 @@ (ptk/reify ::paste-from-event ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) edit-id (dm/get-in state [:workspace-local :edition]) is-editing? (and edit-id (= :text (get-in objects [edit-id :type])))] @@ -1516,8 +1519,8 @@ (ptk/reify ::copy-selected-css ptk/EffectEvent (effect [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (->> (wsh/lookup-selected state) (mapv (d/getf objects))) + (let [objects (dsh/lookup-page-objects state) + selected (->> (dsh/lookup-selected state) (mapv (d/getf objects))) css (css/generate-style objects selected selected {:with-prelude? false})] (wapi/write-to-clipboard css))))) @@ -1526,8 +1529,8 @@ (ptk/reify ::copy-selected-css-nested ptk/EffectEvent (effect [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (->> (wsh/lookup-selected state) + (let [objects (dsh/lookup-page-objects state) + selected (->> (dsh/lookup-selected state) (cfh/selected-with-children objects) (mapv (d/getf objects))) css (css/generate-style objects selected selected {:with-prelude? false})] @@ -1564,14 +1567,14 @@ (js/console.error "clipboard blocked:" error) (rx/empty))] - (let [selected (->> (wsh/lookup-selected state) first) - objects (wsh/lookup-page-objects state)] + (let [selected (->> (dsh/lookup-selected state) first) + objects (dsh/lookup-page-objects state)] (when-let [shape (get objects selected)] (let [props (cts/extract-props shape) features (-> (features/get-team-enabled-features state) (set/difference cfeat/frontend-only-features)) - version (dm/get-in state [:workspace-file :version]) + version (-> (dsh/lookup-file state) :version) copy-data {:type :copied-props :features features @@ -1628,8 +1631,8 @@ (rx/catch on-error)))))) (defn selected-frame? [state] - (let [selected (wsh/lookup-selected state) - objects (wsh/lookup-page-objects state)] + (let [selected (dsh/lookup-selected state) + objects (dsh/lookup-page-objects state)] (and (= 1 (count selected)) (= :frame (get-in objects [(first selected) :type]))))) @@ -1643,7 +1646,7 @@ (filter #(contains? parent-ids %))))) (defn any-same-frame-from-selected? [state frame-ids] - (let [selected (first (wsh/lookup-selected state))] + (let [selected (first (dsh/lookup-selected state))] (< 0 (count (filter #(= % selected) frame-ids))))) (defn frame-same-size? @@ -1777,7 +1780,7 @@ ptk/WatchEvent (watch [_ state _] (let [features (features/get-team-enabled-features state) - selected (wsh/lookup-selected state)] + selected (dsh/lookup-selected state)] (when (paste-data-valid? pdata) (cfeat/check-paste-features! features (:features pdata)) @@ -1841,10 +1844,10 @@ change))) (calculate-paste-position [state pobjects selected position] - (let [page-objects (wsh/lookup-page-objects state) + (let [page-objects (dsh/lookup-page-objects state) selected-objs (map (d/getf pobjects) selected) first-selected-obj (first selected-objs) - page-selected (wsh/lookup-selected state) + page-selected (dsh/lookup-selected state) wrapper (gsh/shapes->rect selected-objs) orig-pos (gpt/point (:x1 wrapper) (:y1 wrapper)) frame-id (first page-selected) @@ -1954,7 +1957,7 @@ ptk/WatchEvent (watch [it state _] (let [file-id (:current-file-id state) - page (wsh/lookup-page state) + page (dsh/lookup-page state) media-idx (->> (:images pdata) (d/index-by :prev-id)) @@ -1972,10 +1975,12 @@ page-objects (:objects page) - libraries (wsh/get-libraries state) - ldata (wsh/get-local-file state) + libraries (dsh/lookup-libraries state) + ldata (dsh/lookup-file-data state file-id) - full-libs (assoc-in libraries [(:id ldata) :data] ldata) + ;; full-libs (assoc-in libraries [(:id ldata) :data] ldata) + + full-libs libraries [parent-id frame-id] (ctn/find-valid-parent-and-frame-ids candidate-parent-id page-objects (vals objects) true full-libs) @@ -2053,8 +2058,8 @@ (cond ;; Pasting inside a frame (selected-frame? state) - (let [page-selected (wsh/lookup-selected state) - page-objects (wsh/lookup-page-objects state) + (let [page-selected (dsh/lookup-selected state) + page-objects (dsh/lookup-page-objects state) frame-id (first page-selected) frame-object (get page-objects frame-id)] (gsh/shape->center frame-object)) @@ -2133,7 +2138,7 @@ (ptk/reify ::paste-image ptk/WatchEvent (watch [_ state _] - (let [file-id (dm/get-in state [:workspace-file :id]) + (let [file-id (:current-file-id state) position (calculate-paste-position state) params {:file-id file-id :blobs [image] @@ -2177,7 +2182,7 @@ ptk/WatchEvent (watch [it state _] (let [page-id (or page-id (:current-page-id state)) - page (wsh/lookup-page state page-id) + page (dsh/lookup-page state page-id) changes (-> (pcb/empty-changes it) (pcb/with-page page) (pcb/mod-page {:background (:color color)}))] @@ -2214,12 +2219,24 @@ ;; Orphan Shapes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defn- find-orphan-shapes + ([state] + (find-orphan-shapes state (:current-page-id state))) + ([state page-id] + (let [objects (dsh/lookup-page-objects state page-id) + objects (filter (fn [item] + (and + (not= (key item) uuid/zero) + (not (contains? objects (:parent-id (val item)))))) + objects)] + objects))) + (defn fix-orphan-shapes [] (ptk/reify ::fix-orphan-shapes ptk/WatchEvent (watch [_ state _] - (let [orphans (set (into [] (keys (wsh/find-orphan-shapes state))))] + (let [orphans (set (into [] (keys (find-orphan-shapes state))))] (rx/of (relocate-shapes orphans uuid/zero 0 true)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2254,7 +2271,9 @@ (ptk/reify ::update-component-annotation ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [data + (dsh/lookup-file-data state) + update-fn (fn [component] ;; NOTE: we need to ensure the component exists, @@ -2265,9 +2284,10 @@ (dissoc component :annotation) (assoc component :annotation annotation)))) - changes (-> (pcb/empty-changes it) - (pcb/with-library-data data) - (pcb/update-component id update-fn))] + changes + (-> (pcb/empty-changes it) + (pcb/with-library-data data) + (pcb/update-component id update-fn))] (rx/concat (rx/of (dch/commit-changes changes)) @@ -2323,7 +2343,7 @@ (ptk/reify ::find-components-norefs ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) copies (->> objects vals (filter #(and (ctk/instance-head? %) (not (ctk/main-instance? %))))) diff --git a/frontend/src/app/main/data/workspace/bool.cljs b/frontend/src/app/main/data/workspace/bool.cljs index 013a2dbe6..55049b512 100644 --- a/frontend/src/app/main/data/workspace/bool.cljs +++ b/frontend/src/app/main/data/workspace/bool.cljs @@ -16,17 +16,17 @@ [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [beicon.v2.core :as rx] [cuerdas.core :as str] [potok.v2.core :as ptk])) (defn selected-shapes-idx [state] - (let [objects (wsh/lookup-page-objects state)] - (->> (wsh/lookup-selected state) + (let [objects (dsh/lookup-page-objects state)] + (->> (dsh/lookup-selected state) (cph/clean-loops objects)))) (defn create-bool-data @@ -91,9 +91,9 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state) + objects (dsh/lookup-page-objects state) name (-> bool-type d/name str/capital) - ids (->> (or ids (wsh/lookup-selected state)) + ids (->> (or ids (dsh/lookup-selected state)) (cph/clean-loops objects)) ordered-indexes (cph/order-by-indexed-shapes objects ids) shapes (->> ordered-indexes @@ -121,7 +121,7 @@ (ptk/reify ::group-to-bool ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) change-to-bool (fn [shape] (group->bool shape bool-type objects))] (when-not (ctn/has-any-copy-parent? objects (get objects shape-id)) @@ -132,7 +132,7 @@ (ptk/reify ::bool-to-group ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) change-to-group (fn [shape] (bool->group shape objects))] (when-not (ctn/has-any-copy-parent? objects (get objects shape-id)) @@ -144,7 +144,7 @@ (ptk/reify ::change-bool-type ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) change-type (fn [shape] (assoc shape :bool-type bool-type))] (when-not (ctn/has-any-copy-parent? objects (get objects shape-id)) diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index 2723206e7..85c096a46 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -17,11 +17,11 @@ [app.common.types.shape.shadow :refer [check-shadow!]] [app.main.broadcast :as mbc] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.modal :as md] [app.main.data.workspace.layout :as layout] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.texts :as dwt] [app.main.data.workspace.undo :as dwu] [app.util.storage :as storage] @@ -84,8 +84,7 @@ (defn transform-fill ([state ids color transform] (transform-fill state ids color transform nil)) ([state ids color transform options] - (let [objects (wsh/lookup-page-objects state) - + (let [objects (dsh/lookup-page-objects state) is-text? #(= :text (:type (get objects %))) text-ids (filter is-text? ids) shape-ids (remove is-text? ids) @@ -135,7 +134,7 @@ (ptk/reify ::reorder-fills ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) is-text? #(= :text (:type (get objects %))) text-ids (filter is-text? ids) @@ -234,7 +233,7 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) is-text? #(= :text (:type (get objects %))) shape-ids (filter (complement is-text?) ids) attrs {:hide-fill-on-export hide-fill-on-export}] @@ -436,7 +435,7 @@ (ptk/reify ::picker-for-selected-shape ptk/WatchEvent (watch [_ state stream] - (let [ids (wsh/lookup-selected state) + (let [ids (dsh/lookup-selected state) stop? (rx/filter (ptk/type? ::stop-picker) stream) update-events @@ -541,8 +540,8 @@ (ptk/reify ::apply-color-from-palette ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (->> (wsh/lookup-selected state) + (let [objects (dsh/lookup-page-objects state) + selected (->> (dsh/lookup-selected state) (cfh/clean-loops objects)) ids @@ -716,7 +715,7 @@ (ptk/reify ::update-colorpicker ptk/UpdateEvent (update [_ state] - (let [shape-id (-> state wsh/lookup-selected first)] + (let [shape-id (-> state dsh/lookup-selected first)] (update state :colorpicker (fn [state] (let [current-color (:current-color state)] @@ -978,8 +977,8 @@ (ptk/reify ::select-color ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) - shapes (wsh/lookup-shapes state selected) + (let [selected (dsh/lookup-selected state) + shapes (dsh/lookup-shapes state selected) shape (first shapes) fills (if (cfh/text-shape? shape) (:fills (dwt/current-text-values diff --git a/frontend/src/app/main/data/workspace/comments.cljs b/frontend/src/app/main/data/workspace/comments.cljs index 2eb9a26ff..2ccacdece 100644 --- a/frontend/src/app/main/data/workspace/comments.cljs +++ b/frontend/src/app/main/data/workspace/comments.cljs @@ -17,11 +17,11 @@ [app.main.data.comments :as dcmt] [app.main.data.common :as dcm] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.workspace.common :as dwco] [app.main.data.workspace.drawing :as dwd] [app.main.data.workspace.edition :as dwe] [app.main.data.workspace.selection :as dws] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.viewport :as dwv] [app.main.repo :as rp] [app.main.router :as rt] @@ -35,26 +35,25 @@ (defn initialize-comments [file-id] - (dm/assert! (uuid? file-id)) (ptk/reify ::initialize-comments ptk/WatchEvent (watch [_ _ stream] - (let [stopper (rx/filter #(= ::finalize %) stream)] - (rx/merge - (rx/of (dcmt/retrieve-comment-threads file-id)) - (->> stream - (rx/filter mse/mouse-event?) - (rx/filter mse/mouse-click-event?) - (rx/switch-map #(rx/take 1 ms/mouse-position)) - (rx/with-latest-from ms/keyboard-space) - (rx/filter (fn [[_ space]] (not space))) - (rx/map first) - (rx/map handle-comment-layer-click) - (rx/take-until stopper)) - (->> stream - (rx/filter dwco/interrupt?) - (rx/map handle-interrupt) - (rx/take-until stopper))))))) + (let [stopper-s (rx/filter #(= ::finalize %) stream)] + (->> (rx/merge + (rx/of (dcmt/retrieve-comment-threads file-id)) + (->> stream + (rx/filter mse/mouse-event?) + (rx/filter mse/mouse-click-event?) + (rx/switch-map #(rx/take 1 ms/mouse-position)) + (rx/with-latest-from ms/keyboard-space) + (rx/filter (fn [[_ space]] (not space))) + (rx/map first) + (rx/map handle-comment-layer-click)) + (->> stream + (rx/filter dwco/interrupt?) + (rx/map handle-interrupt))) + + (rx/take-until stopper-s)))))) (defn- handle-interrupt [] @@ -65,10 +64,8 @@ (cond (:draft local) (rx/of (dcmt/close-thread)) (:open local) (rx/of (dcmt/close-thread)) - - :else - (rx/of (dwe/clear-edition-mode) - (dws/deselect-all true))))))) + :else (rx/of (dwe/clear-edition-mode) + (dws/deselect-all true))))))) ;; Event responsible of the what should be executed when user clicked ;; on the comments layer. An option can be create a new draft thread, @@ -139,9 +136,9 @@ (ptk/reify ::update-comment-thread-position ptk/WatchEvent (watch [it state _] - (let [page (wsh/lookup-page state) + (let [page (dsh/lookup-page state) page-id (:id page) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) frame-id (if (nil? frame-id) (ctst/get-frame-id-by-position objects (gpt/point new-x new-y)) (:frame-id thread)) @@ -172,7 +169,7 @@ (ptk/reify ::move-frame-comment-threads ptk/WatchEvent (watch [_ state _] - (let [page (wsh/lookup-page state) + (let [page (dsh/lookup-page state) objects (get page :objects) is-frame? (fn [id] (= :frame (get-in objects [id :type]))) diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index a595a8c3f..eefffe628 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -20,8 +20,8 @@ [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.constants :refer [zoom-half-pixel-precision]] + [app.main.data.helpers :as dsh] [app.main.data.workspace.drawing.common :as common] - [app.main.data.workspace.state-helpers :as wsh] [app.main.snap :as snap] [app.main.streams :as ms] [app.util.array :as array] @@ -87,7 +87,7 @@ initial (cond-> @ms/mouse-position snap-pixel? (gpt/round-step snap-prec)) page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) focus (:workspace-focus-selected state) fid (->> (ctst/top-nested-frame objects initial) diff --git a/frontend/src/app/main/data/workspace/drawing/common.cljs b/frontend/src/app/main/data/workspace/drawing/common.cljs index fffc73b00..dc565bfdf 100644 --- a/frontend/src/app/main/data/workspace/drawing/common.cljs +++ b/frontend/src/app/main/data/workspace/drawing/common.cljs @@ -12,8 +12,8 @@ [app.common.math :as mth] [app.common.types.modifiers :as ctm] [app.common.types.shape :as cts] + [app.main.data.helpers :as dsh] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.worker :as uw] [beicon.v2.core :as rx] @@ -33,7 +33,7 @@ (watch [_ state _] (let [tool (dm/get-in state [:workspace-drawing :tool]) shape (dm/get-in state [:workspace-drawing :object]) - objects (wsh/lookup-page-objects state) + objects (dsh/lookup-page-objects state) page-id (:current-page-id state)] (rx/concat diff --git a/frontend/src/app/main/data/workspace/drawing/curve.cljs b/frontend/src/app/main/data/workspace/drawing/curve.cljs index 5c0d98898..7a4225096 100644 --- a/frontend/src/app/main/data/workspace/drawing/curve.cljs +++ b/frontend/src/app/main/data/workspace/drawing/curve.cljs @@ -18,8 +18,8 @@ [app.common.types.shape-tree :as ctst] [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] + [app.main.data.helpers :as dsh] [app.main.data.workspace.drawing.common :as common] - [app.main.data.workspace.state-helpers :as wsh] [app.main.streams :as ms] [app.util.mouse :as mse] [app.util.path.simplify-curve :as ups] @@ -51,7 +51,7 @@ (ptk/reify ::setup-frame ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) content (dm/get-in state [:workspace-drawing :object :content] []) start (dm/get-in content [0 :params] nil) position (when start (gpt/point start)) diff --git a/frontend/src/app/main/data/workspace/edition.cljs b/frontend/src/app/main/data/workspace/edition.cljs index 97edd0649..e4fdf6cce 100644 --- a/frontend/src/app/main/data/workspace/edition.cljs +++ b/frontend/src/app/main/data/workspace/edition.cljs @@ -7,8 +7,8 @@ (ns app.main.data.workspace.edition (:require [app.common.data.macros :as dm] + [app.main.data.helpers :as dsh] [app.main.data.workspace.path.common :as dwpc] - [app.main.data.workspace.state-helpers :as wsh] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -22,7 +22,7 @@ (ptk/reify ::start-edition-mode ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state)] + (let [objects (dsh/lookup-page-objects state)] ;; Can only edit objects that exist (if (contains? objects id) (-> state @@ -38,7 +38,10 @@ (rx/take 1) (rx/map clear-edition-mode))))) -;; If these event change modules review /src/app/main/data/workspace/path/undo.cljs +;; IMPORTANT: If this event is moved from this namespace to other, +;; update namespace reference in the +;; app/main/data/workspace/path/undo.cljs file. + (defn clear-edition-mode [] (ptk/reify ::clear-edition-mode diff --git a/frontend/src/app/main/data/workspace/fix_broken_shapes.cljs b/frontend/src/app/main/data/workspace/fix_broken_shapes.cljs index ae19af68a..78f88dc82 100644 --- a/frontend/src/app/main/data/workspace/fix_broken_shapes.cljs +++ b/frontend/src/app/main/data/workspace/fix_broken_shapes.cljs @@ -7,6 +7,7 @@ (ns app.main.data.workspace.fix-broken-shapes (:require [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -39,12 +40,12 @@ (ptk/reify ::fix-broken-shapes ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [fdata (dsh/lookup-file-data state) changes (concat (mapcat (partial generate-broken-link-changes :page-id) - (vals (:pages-index data))) + (vals (:pages-index fdata))) (mapcat (partial generate-broken-link-changes :component-id) - (vals (:components data))))] + (vals (:components fdata))))] (if (seq changes) (rx/of (dch/commit-changes diff --git a/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs b/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs index 75f7c83d2..0b6cb61d5 100644 --- a/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs +++ b/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs @@ -9,7 +9,7 @@ [app.common.files.helpers :as cfh] [app.common.text :as txt] [app.main.data.changes :as dwc] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [app.main.fonts :as fonts] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -91,7 +91,7 @@ objects)) (defn- generate-deleted-font-components-changes - [state] + [fdata] (sequence (comp (map val) (filter should-fix-deleted-font-component?) @@ -99,27 +99,29 @@ {:type :mod-component :id (:id component) :objects (-> (fix-deleted-font-component component) :objects)}))) - (wsh/lookup-local-components state))) + (:components fdata))) (defn- generate-deleted-font-typography-changes - [state] + [fdata] (sequence (comp (map val) (filter has-invalid-font-family?) (map (fn [typography] {:type :mod-typography :typography (fix-deleted-font-typography typography)}))) - (get-in state [:workspace-data :typographies]))) + (:typographies fdata))) (defn fix-deleted-fonts [] (ptk/reify ::fix-deleted-fonts ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) - shape-changes (mapcat generate-deleted-font-shape-changes (vals (:pages-index data))) - components-changes (generate-deleted-font-components-changes state) - typography-changes (generate-deleted-font-typography-changes state) + (let [fdata (dsh/lookup-file-data state) + pages (:pages-index fdata) + + shape-changes (mapcat generate-deleted-font-shape-changes (vals pages)) + components-changes (generate-deleted-font-components-changes fdata) + typography-changes (generate-deleted-font-typography-changes fdata) changes (concat shape-changes components-changes typography-changes)] diff --git a/frontend/src/app/main/data/workspace/grid.cljs b/frontend/src/app/main/data/workspace/grid.cljs index 3187c925b..b6876e69b 100644 --- a/frontend/src/app/main/data/workspace/grid.cljs +++ b/frontend/src/app/main/data/workspace/grid.cljs @@ -11,8 +11,8 @@ [app.common.files.changes-builder :as pcb] [app.common.types.grid :as ctg] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -26,8 +26,7 @@ (ptk/reify ::add-frame-grid ptk/WatchEvent (watch [_ state _] - (let [page-id (:current-page-id state) - page (dm/get-in state [:workspace-data :pages-index page-id]) + (let [page (dsh/lookup-page state) params (or (dm/get-in page [:default-grids :square]) (:square ctg/default-grid-params)) grid {:type :square @@ -56,7 +55,7 @@ (ptk/reify ::set-default-grid ptk/WatchEvent (watch [it state _] - (let [page (wsh/lookup-page state)] + (let [page (dsh/lookup-page state)] (rx/of (dch/commit-changes (-> (pcb/empty-changes it) (pcb/with-page page) diff --git a/frontend/src/app/main/data/workspace/grid_layout/editor.cljs b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs index 9af194119..79c143bec 100644 --- a/frontend/src/app/main/data/workspace/grid_layout/editor.cljs +++ b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs @@ -9,7 +9,7 @@ [app.common.data.macros :as dm] [app.common.geom.rect :as grc] [app.common.types.shape.layout :as ctl] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [potok.v2.core :as ptk])) (defn hover-grid-cell @@ -34,7 +34,7 @@ ptk/UpdateEvent (update [_ state] (if shift? - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) grid (get objects grid-id) selected (or (dm/get-in state [:workspace-grid-edition grid-id :selected]) #{}) selected (into selected [cell-id]) @@ -74,7 +74,7 @@ (ptk/reify ::clean-selection ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects grid-id)] (update-in state [:workspace-grid-edition grid-id :selected] (fn [selected] @@ -94,7 +94,7 @@ (ptk/reify ::locate-board ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) srect (get-in objects [grid-id :selrect])] (-> state (update :workspace-local @@ -111,7 +111,7 @@ (ptk/reify ::select-track-cells ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) parent (get objects grid-id) cells diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index 04beaa553..b0f97b055 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -17,8 +17,8 @@ [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.workspace.selection :as dws] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -182,7 +182,7 @@ (watch [it state _] (let [id (d/nilv id (uuid/next)) page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shapes (->> ids @@ -203,7 +203,7 @@ (ptk/reify ::group-selected ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (rx/of (group-shapes nil selected :change-selection? true)))))) (defn ungroup-shapes @@ -212,7 +212,7 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) prepare (fn [shape-id] @@ -264,7 +264,7 @@ (ptk/reify ::ungroup-selected ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (rx/of (ungroup-shapes selected :change-selection? true)))))) (defn mask-group @@ -275,8 +275,8 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (->> (or ids (wsh/lookup-selected state)) + objects (dsh/lookup-page-objects state page-id) + selected (->> (or ids (dsh/lookup-selected state)) (cfh/clean-loops objects) (remove #(ctn/has-any-copy-parent? objects (get objects %)))) shapes (shapes-for-grouping objects selected) @@ -323,9 +323,9 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) - masked-groups (->> (d/nilv ids (wsh/lookup-selected state)) + masked-groups (->> (d/nilv ids (dsh/lookup-selected state)) (map #(get objects %)) (filter #(or (= :bool (:type %)) (= :group (:type %))))) diff --git a/frontend/src/app/main/data/workspace/guides.cljs b/frontend/src/app/main/data/workspace/guides.cljs index 4ecfaba63..eba5eb2c7 100644 --- a/frontend/src/app/main/data/workspace/guides.cljs +++ b/frontend/src/app/main/data/workspace/guides.cljs @@ -13,7 +13,7 @@ [app.common.types.page :as ctp] [app.main.data.changes :as dwc] [app.main.data.event :as ev] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -31,7 +31,7 @@ ptk/WatchEvent (watch [it state _] - (let [page (wsh/lookup-page state) + (let [page (dsh/lookup-page state) changes (-> (pcb/empty-changes it) (pcb/with-page page) @@ -56,7 +56,7 @@ ptk/WatchEvent (watch [it state _] - (let [page (wsh/lookup-page state) + (let [page (dsh/lookup-page state) changes (-> (pcb/empty-changes it) (pcb/with-page page) @@ -73,7 +73,7 @@ (ptk/reify ::remove-guides ptk/WatchEvent (watch [_ state _] - (let [{:keys [guides] :as page} (wsh/lookup-page state) + (let [{:keys [guides] :as page} (dsh/lookup-page state) guides (-> (select-keys guides ids) (vals))] (rx/from (mapv remove-guide guides)))))) @@ -88,7 +88,7 @@ (let [ids (:ids args) object-modifiers (:modifiers args) - objects (wsh/lookup-page-objects state) + objects (dsh/lookup-page-objects state) is-frame? (fn [id] (= :frame (get-in objects [id :type]))) frame-ids? (into #{} (filter is-frame?) ids) @@ -104,7 +104,7 @@ guide (update guide :position + (get moved (:axis guide)))] (update-guides guide))) - guides (-> state wsh/lookup-page :guides vals)] + guides (-> state dsh/lookup-page :guides vals)] (->> guides (filter (comp frame-ids? :frame-id)) diff --git a/frontend/src/app/main/data/workspace/interactions.cljs b/frontend/src/app/main/data/workspace/interactions.cljs index 978413941..f9f64f3a2 100644 --- a/frontend/src/app/main/data/workspace/interactions.cljs +++ b/frontend/src/app/main/data/workspace/interactions.cljs @@ -18,8 +18,8 @@ [app.common.uuid :as uuid] [app.main.data.changes :as dch] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.streams :as ms] [app.util.mouse :as mse] @@ -41,8 +41,8 @@ ptk/WatchEvent (watch [it state _] (let [page (if page-id - (wsh/lookup-page state page-id) - (wsh/lookup-page state)) + (dsh/lookup-page state page-id) + (dsh/lookup-page state)) flows (get page :flows) unames (cfh/get-used-names (vals flows)) @@ -64,7 +64,7 @@ (ptk/reify ::add-flow-selected-frame ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (rx/of (add-flow (first selected))))))) (defn remove-flow @@ -77,8 +77,8 @@ ptk/WatchEvent (watch [it state _] (let [page (if page-id - (wsh/lookup-page state page-id) - (wsh/lookup-page state))] + (dsh/lookup-page state page-id) + (dsh/lookup-page state))] (rx/of (dch/commit-changes (-> (pcb/empty-changes it) (pcb/with-page page) @@ -94,8 +94,8 @@ ptk/WatchEvent (watch [it state _] (let [page (if page-id - (wsh/lookup-page state page-id) - (wsh/lookup-page state)) + (dsh/lookup-page state page-id) + (dsh/lookup-page state)) flow (dm/get-in page [:flows flow-id]) flow (some-> flow update-fn)] @@ -114,7 +114,7 @@ (ptk/reify ::rename-flow ptk/WatchEvent (watch [_ state _] - (let [page (wsh/lookup-page state)] + (let [page (dsh/lookup-page state)] (rx/of (update-flow (:id page) flow-id #(assoc % :name name))))))) (defn start-rename-flow @@ -165,7 +165,7 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - page (wsh/lookup-page state page-id) + page (dsh/lookup-page state page-id) objects (get page :objects) frame (cfh/get-root-frame objects (:id shape)) @@ -229,7 +229,7 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) remove-interactions-shape (fn [shape] @@ -258,7 +258,7 @@ ptk/WatchEvent (watch [_ state stream] (let [initial-pos @ms/mouse-position - selected (wsh/lookup-selected state) + selected (dsh/lookup-selected state) stopper (mse/drag-stopper stream)] (when (= 1 (count selected)) (rx/concat @@ -270,9 +270,9 @@ (defn- get-target-frame [state position] - (let [objects (wsh/lookup-page-objects state) - from-id (-> state wsh/lookup-selected first) - from-shape (wsh/lookup-shape state from-id) + (let [objects (dsh/lookup-page-objects state) + from-id (-> state dsh/lookup-selected first) + from-shape (dsh/lookup-shape state from-id) from-frame-id (if (cfh/frame-shape? from-shape) from-id (:frame-id from-shape)) @@ -309,8 +309,8 @@ (watch [_ state _] (let [position @ms/mouse-position target-frame (get-target-frame state position) - shape-id (-> state wsh/lookup-selected first) - shape (wsh/lookup-shape state shape-id) + shape-id (-> state dsh/lookup-selected first) + shape (dsh/lookup-shape state shape-id) change-interaction (fn [interaction] @@ -368,13 +368,13 @@ ptk/WatchEvent (watch [_ state stream] (let [initial-pos @ms/mouse-position - selected (wsh/lookup-selected state) + selected (dsh/lookup-selected state) stopper (mse/drag-stopper stream)] (when (= 1 (count selected)) (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shape (->> state - wsh/lookup-selected + dsh/lookup-selected first (get objects)) overlay-pos (-> shape @@ -418,9 +418,9 @@ (gpt/subtract offset)) page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shape (->> state - wsh/lookup-selected + dsh/lookup-selected first (get objects)) diff --git a/frontend/src/app/main/data/workspace/layers.cljs b/frontend/src/app/main/data/workspace/layers.cljs index 3425a16a4..cf655f4b0 100644 --- a/frontend/src/app/main/data/workspace/layers.cljs +++ b/frontend/src/app/main/data/workspace/layers.cljs @@ -9,8 +9,8 @@ (:require [app.common.data :as d] [app.common.math :as mth] + [app.main.data.helpers :as dsh] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [beicon.v2.core :as rx] [cuerdas.core :as str] [potok.v2.core :as ptk])) @@ -43,8 +43,8 @@ (ptk/reify ::set-opacity ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (wsh/lookup-selected state {:omit-blocked? true}) + (let [objects (dsh/lookup-page-objects state) + selected (dsh/lookup-selected state {:omit-blocked? true}) shapes (map #(get objects %) selected) shapes-ids (->> shapes (map :id))] diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 39b870cec..8af6545be 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -29,6 +29,7 @@ [app.main.data.comments :as dc] [app.main.data.common :as dcm] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.modal :as modal] [app.main.data.notifications :as ntf] [app.main.data.workspace :as-alias dw] @@ -37,7 +38,6 @@ [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.specialized-panel :as dwsp] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.thumbnails :as dwt] [app.main.data.workspace.transforms :as dwtr] [app.main.data.workspace.undo :as dwu] @@ -63,7 +63,7 @@ [file-id state] (if (= file-id (:current-file-id state)) "" - (str "<" (get-in state [:libraries file-id :name]) ">"))) + (str "<" (get-in state [:files file-id :name]) ">"))) (defn- log-changes [changes file] @@ -164,16 +164,16 @@ (defn- update-color* [it state color file-id] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) [path name] (cfh/parse-path-name (:name color)) color (assoc color :path path :name name) changes (-> (pcb/empty-changes it) (pcb/with-library-data data) (pcb/update-color color)) - undo-id (js/Symbol)] + undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) (dch/commit-changes changes) - (sync-file (:current-file-id state) file-id :colors (:id color)) + (sync-file (:id data) file-id :colors (:id color)) (dwu/commit-undo-transaction undo-id)))) (defn update-color @@ -212,6 +212,7 @@ (let [color (assoc color :name (dm/str (:path color) "/" (:name color)))] (update-color* it state color file-id)))))) +;; FIXME: revisit why file-id is passed on the event (defn rename-color [file-id id new-name] (dm/assert! @@ -232,7 +233,7 @@ (let [new-name (str/trim new-name)] (if (str/empty? new-name) (rx/empty) - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) color (get-in data [:colors id]) color (assoc color :name new-name) color (d/without-nils color)] @@ -247,7 +248,7 @@ ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) changes (-> (pcb/empty-changes it) (pcb/with-library-data data) (pcb/delete-color id))] @@ -288,7 +289,7 @@ (if (str/empty? new-name) (rx/empty) (let [[path name] (cfh/parse-path-name new-name) - data (get state :workspace-data) + data (dsh/lookup-file-data state) object (get-in data [:media id]) new-object (assoc object :path path :name name) changes (-> (pcb/empty-changes it) @@ -308,7 +309,7 @@ ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) changes (-> (pcb/empty-changes it) (pcb/with-library-data data) (pcb/delete-media id))] @@ -337,7 +338,7 @@ (defn- do-update-tipography [it state typography file-id] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) typography (extract-path-if-missing typography) changes (-> (pcb/empty-changes it) (pcb/with-library-data data) @@ -373,7 +374,7 @@ ptk/WatchEvent (watch [it state _] (when (and (some? new-name) (not= "" new-name)) - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) [path name] (cfh/parse-path-name new-name) object (get-in data [:typographies id]) new-object (assoc object :path path :name name)] @@ -388,7 +389,7 @@ ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) changes (-> (pcb/empty-changes it) (pcb/with-library-data data) (pcb/delete-typography id))] @@ -409,7 +410,7 @@ (watch [it state _] (let [file-id (:current-file-id state) page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shapes (dwg/shapes-for-grouping objects selected) parents (into #{} (map :parent-id) shapes)] (when-not (empty? shapes) @@ -436,8 +437,8 @@ (ptk/reify ::add-component ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (->> (d/nilv ids (wsh/lookup-selected state)) + (let [objects (dsh/lookup-page-objects state) + selected (->> (d/nilv ids (dsh/lookup-selected state)) (cfh/clean-loops objects)) selected-objects (map #(get objects %) selected) components-v2 (features/active-feature? state "components/v2") @@ -454,8 +455,8 @@ ptk/WatchEvent (watch [_ state _] (let [components-v2 (features/active-feature? state "components/v2") - objects (wsh/lookup-page-objects state) - selected (->> (wsh/lookup-selected state) + objects (dsh/lookup-page-objects state) + selected (->> (dsh/lookup-selected state) (cfh/clean-loops objects)) selected-objects (map #(get objects %) selected) ;; We don't want to change the structure of component copies @@ -488,11 +489,9 @@ (let [new-name (str/trim new-name)] (if (str/empty? new-name) (rx/empty) - (let [library-data (get state :workspace-data) - components-v2 (features/active-feature? state "components/v2") - changes (-> (pcb/empty-changes it) - (cll/generate-rename-component id new-name library-data components-v2))] - + (let [data (dsh/lookup-file-data state) + changes (-> (pcb/empty-changes it) + (cll/generate-rename-component id new-name data true))] (rx/of (dch/commit-changes changes)))))))) (defn rename-component-and-main-instance @@ -505,14 +504,17 @@ valid? (and (not (str/ends-with? name "/")) (string? clean-name) (not (str/blank? clean-name))) - component (dm/get-in state [:workspace-data :components component-id])] + data (dsh/lookup-file-data state) + component (dm/get-in data [:components component-id])] + (when (and valid? component) (let [shape-id (:main-instance-id component) page-id (:main-instance-page component)] + (rx/concat (rx/of (rename-component component-id clean-name)) - ;; NOTE: only when components-v2 is enabled + ;; NOTE: only when components-v2 is enabled (when (and shape-id page-id) (rx/of (dwsh/update-shapes [shape-id] #(assoc % :name clean-name) {:page-id page-id :stack-undo? true})))))))))) @@ -522,7 +524,7 @@ (ptk/reify ::duplicate-component ptk/WatchEvent (watch [it state _] - (let [libraries (wsh/get-libraries state) + (let [libraries (dsh/lookup-libraries state) library (get libraries library-id) components-v2 (features/active-feature? state "components/v2") changes (-> (pcb/empty-changes it nil) @@ -540,37 +542,31 @@ (ptk/reify ::delete-component ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data)] - (if (features/active-feature? state "components/v2") - (let [component (ctkl/get-component data id) - page-id (:main-instance-page component) - root-id (:main-instance-id component) - file-id (:current-file-id state) - file (wsh/get-file state file-id) - page (wsh/lookup-page state page-id) - objects (wsh/lookup-page-objects state page-id) - components-v2 (features/active-feature? state "components/v2") - undo-group (uuid/next) - undo-id (js/Symbol) - [all-parents changes] - (-> (pcb/empty-changes it page-id) - ;; Deleting main root triggers component delete - (cls/generate-delete-shapes file page objects #{root-id} {:components-v2 components-v2 - :undo-group undo-group - :undo-id undo-id}))] - (rx/of - (dwu/start-undo-transaction undo-id) - (dwt/clear-thumbnail (:current-file-id state) page-id root-id "component") - (dc/detach-comment-thread #{root-id}) - (dch/commit-changes changes) - (ptk/data-event :layout/update {:ids all-parents :undo-group undo-group}) - (dwu/commit-undo-transaction undo-id))) - (let [page-id (:current-page-id state) - changes (-> (pcb/empty-changes it) - (pcb/with-library-data data) - (pcb/delete-component id page-id))] - (rx/of (dch/commit-changes changes)))))))) + (let [file-id (:current-file-id state) + fdata (dsh/lookup-file-data state file-id) + component (ctkl/get-component fdata id) + page-id (:main-instance-page component) + root-id (:main-instance-id component) + page (dsh/get-page fdata page-id) + objects (:objects page) + + undo-group (uuid/next) + undo-id (js/Symbol) + + [all-parents changes] + (-> (pcb/empty-changes it page-id) + ;; Deleting main root triggers component delete + (cls/generate-delete-shapes fdata page objects #{root-id} {:components-v2 true + :undo-group undo-group + :undo-id undo-id}))] + (rx/of + (dwu/start-undo-transaction undo-id) + (dwt/clear-thumbnail (:current-file-id state) page-id root-id "component") + (dc/detach-comment-thread #{root-id}) + (dch/commit-changes changes) + (ptk/data-event :layout/update {:ids all-parents :undo-group undo-group}) + (dwu/commit-undo-transaction undo-id)))))) (defn restore-component "Restore a deleted component, with the given id, in the given file library." @@ -580,12 +576,14 @@ (ptk/reify ::restore-component ptk/WatchEvent (watch [it state _] - (let [page-id (:current-page-id state) - current-page (dm/get-in state [:workspace-data :pages-index page-id]) - library-data (wsh/get-file state library-id) - objects (wsh/lookup-page-objects state page-id) - changes (-> (pcb/empty-changes it) - (cll/generate-restore-component library-data component-id library-id current-page objects))] + (let [page-id (:current-page-id state) + page (dsh/lookup-page state page-id) + objects (:objects page) + + ldata (dsh/lookup-file-data state library-id) + + changes (-> (pcb/empty-changes it) + (cll/generate-restore-component ldata component-id library-id page objects))] (rx/of (dch/commit-changes changes)))))) @@ -614,8 +612,8 @@ (ptk/reify ::instantiate-component ptk/WatchEvent (watch [it state _] - (let [page (wsh/lookup-page state) - libraries (wsh/get-libraries state) + (let [page (dsh/lookup-page state) + libraries (dsh/lookup-libraries state) objects (:objects page) changes (-> (pcb/empty-changes it (:id page)) @@ -637,11 +635,10 @@ (when id-ref (reset! id-ref (:id new-shape))) - (rx/of (ptk/event - ::ev/event - {::ev/name "use-library-component" - ::ev/origin origin - :external-library (not= file-id current-file-id)}) + (rx/of (ptk/event ::ev/event + {::ev/name "use-library-component" + ::ev/origin origin + :external-library (not= file-id current-file-id)}) (dwu/start-undo-transaction undo-id) (dch/commit-changes changes) (ptk/data-event :layout/update {:ids [(:id new-shape)]}) @@ -658,12 +655,14 @@ (ptk/reify ::detach-component ptk/WatchEvent (watch [it state _] - (let [file (wsh/get-local-file state) - page-id (get state :current-page-id) - libraries (wsh/get-libraries state) + (let [page-id (:current-page-id state) + file-id (:current-file-id state) + + fdata (dsh/lookup-file-data state file-id) + libraries (dsh/lookup-libraries state) changes (-> (pcb/empty-changes it) - (cll/generate-detach-component id file page-id libraries))] + (cll/generate-detach-component id fdata page-id libraries))] (rx/of (dch/commit-changes changes)))))) @@ -685,20 +684,27 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - file (wsh/get-local-file state) - libraries (wsh/get-libraries state) + file-id (:current-file-id state) + + ;; FIXME: revisit, innefficient access + objects (dsh/lookup-page-objects state page-id) + + libraries (dsh/lookup-libraries state) + fdata (dsh/lookup-file-data state file-id) + selected (->> state - (wsh/lookup-selected) + (dsh/lookup-selected) (cfh/clean-loops objects)) + selected-objects (map #(get objects %) selected) copies (filter ctk/in-component-copy? selected-objects) can-detach? (and (seq copies) (every? #(not (ctn/has-any-copy-parent? objects %)) selected-objects)) + changes (when can-detach? (reduce (fn [changes id] - (cll/generate-detach-component changes id file page-id libraries)) + (cll/generate-detach-component changes id fdata page-id libraries)) (pcb/empty-changes it) selected))] @@ -725,6 +731,7 @@ ptk/WatchEvent (watch [_ state stream] (let [current-page-id (:current-page-id state) + data (dsh/lookup-file-data state) select-and-zoom (fn [shape-id] @@ -741,7 +748,7 @@ (rx/observe-on :async) (rx/mapcat (fn [_] (select-and-zoom shape-id))))))] - (when-let [component (dm/get-in state [:workspace-data :components id])] + (when-let [component (dm/get-in data [:components id])] (let [page-id (:main-instance-page component) shape-id (:main-instance-id component)] (when (some? page-id) @@ -779,9 +786,9 @@ ptk/UpdateEvent (update [_ state] (-> state - (update-in [:libraries library-id] + (update-in [:files library-id] assoc :modified-at modified-at :revn revn) - (d/update-in-when [:libraries library-id :data] + (d/update-in-when [:files library-id :data] ch/process-changes changes))) ptk/WatchEvent @@ -805,30 +812,25 @@ ptk/WatchEvent (watch [it state _] (log/info :msg "RESET-COMPONENT of shape" :id (str id)) - (let [file (wsh/get-local-file state) - file-full (wsh/get-local-file-full state) - libraries (wsh/get-libraries state) - + (let [libraries (:files state) page-id (:current-page-id state) - container (ctn/get-container file :page page-id) - components-v2 - (features/active-feature? state "components/v2") + file (dsh/lookup-file state) + data (:data file) + container (ctn/get-container data :page page-id) undo-id (js/Symbol) changes (-> (pcb/empty-changes it) - (cll/generate-reset-component file-full libraries container id components-v2))] + (cll/generate-reset-component file libraries container id true))] (log/debug :msg "RESET-COMPONENT finished" :js/rchanges (log-changes (:redo-changes changes) file)) - - (rx/of - (dwu/start-undo-transaction undo-id) - (dch/commit-changes changes) - (dwu/commit-undo-transaction undo-id)))))) + (rx/of (dwu/start-undo-transaction undo-id) + (dch/commit-changes changes) + (dwu/commit-undo-transaction undo-id)))))) (defn reset-components "Cancels all modifications in the shapes with the given ids" @@ -859,24 +861,24 @@ ptk/WatchEvent (watch [it state _] (log/info :msg "UPDATE-COMPONENT of shape" :id (str id) :undo-group undo-group) - (let [page-id (get state :current-page-id) - local-file (wsh/get-local-file state) - full-file (wsh/get-local-file-full state) - container (ctn/get-container local-file :page page-id) - shape (ctn/get-shape container id) - components-v2 (features/active-feature? state "components/v2")] + (let [page-id (:current-page-id state) + + libraries (dsh/lookup-libraries state) + file (dsh/lookup-file state) + fdata (:data file) + + container (ctn/get-container fdata :page page-id) + shape (ctn/get-shape container id)] (when (ctk/instance-head? shape) - (let [libraries (wsh/get-libraries state) - - changes + (let [changes (-> (pcb/empty-changes it) (pcb/set-undo-group undo-group) (pcb/with-container container) - (cll/generate-sync-shape-inverse full-file libraries container id components-v2)) + (cll/generate-sync-shape-inverse fdata libraries container id true)) - file-id (:component-file shape) - file (wsh/get-file state file-id) + ldata (->> (:component-file shape) + (dsh/lookup-file-data state)) xf-filter (comp (filter :local-change?) @@ -897,29 +899,25 @@ (log/debug :msg "UPDATE-COMPONENT finished" :js/local-changes (log-changes (:redo-changes local-changes) - file) + fdata) :js/nonlocal-changes (log-changes (:redo-changes nonlocal-changes) - file)) + fdata)) (rx/of (when (seq (:redo-changes local-changes)) (dch/commit-changes (assoc local-changes - :file-id (:id local-file)))) + :file-id (:id file)))) (when (seq (:redo-changes nonlocal-changes)) (dch/commit-changes (assoc nonlocal-changes - :file-id file-id))))))))))) + :file-id (:id ldata)))))))))))) (defn- update-component-thumbnail-sync [state component-id file-id tag] - (let [current-file-id (:current-file-id state) - current-file? (= current-file-id file-id) - data (if current-file? - (get state :workspace-data) - (get-in state [:libraries file-id :data])) - component (ctkl/get-component data component-id) - page-id (:main-instance-page component) - root-id (:main-instance-id component)] + (let [data (dsh/lookup-file-data state file-id) + component (ctkl/get-component data component-id) + page-id (:main-instance-page component) + root-id (:main-instance-id component)] (dwt/update-thumbnail file-id page-id root-id tag "update-component-thumbnail-sync"))) (defn update-component-sync @@ -930,7 +928,8 @@ (watch [_ state _] (let [current-file-id (:current-file-id state) current-file? (= current-file-id file-id) - page (wsh/lookup-page state) + + page (dsh/lookup-page state) shape (ctn/get-shape page shape-id) component-id (:component-id shape) undo-id (js/Symbol)] @@ -995,12 +994,13 @@ (watch [it state _] ;; First delete shapes so we have space in the layout otherwise we can have problems ;; in the grid creating new rows/columns to make space - (let [file (wsh/get-file state file-id) - libraries (wsh/get-libraries state) - page (wsh/lookup-page state) - objects (wsh/lookup-page-objects state) + (let [libraries (dsh/lookup-libraries state) + page (dsh/lookup-page state) + objects (:objects page) parent (get objects (:parent-id shape)) + ldata (dsh/lookup-file-data state file-id) + ;; If the target parent is a grid layout we need to pass the target cell target-cell (when (ctl/grid-layout? parent) (ctl/get-cell-by-shape-id parent (:id shape))) @@ -1016,7 +1016,7 @@ [new-shape all-parents changes] (-> (pcb/empty-changes it (:id page)) (pcb/set-undo-group undo-group) - (cll/generate-component-swap objects shape file page libraries id-new-component index target-cell keep-props-values))] + (cll/generate-component-swap objects shape ldata page libraries id-new-component index target-cell keep-props-values))] (rx/of (dwu/start-undo-transaction undo-id) @@ -1086,7 +1086,7 @@ (update [_ state] (if (and (not= library-id (:current-file-id state)) (nil? asset-id)) - (d/assoc-in-when state [:libraries library-id :synced-at] (dt/now)) + (d/assoc-in-when state [:files library-id :synced-at] (dt/now)) state)) ptk/WatchEvent @@ -1098,8 +1098,8 @@ :asset-type asset-type :asset-id asset-id :undo-group undo-group) - (let [file (wsh/get-file state file-id) - libraries (wsh/get-libraries state) + (let [ldata (dsh/lookup-file-data state file-id) + libraries (dsh/lookup-libraries state) current-file-id (:current-file-id state) changes (cll/generate-sync-file-changes @@ -1113,7 +1113,7 @@ current-file-id) find-frames (fn [change] - (->> (ch/frames-changed file change) + (->> (ch/frames-changed ldata change) (map #(assoc %1 :page-id (:page-id change))))) updated-frames (->> changes @@ -1123,7 +1123,7 @@ (log/debug :msg "SYNC-FILE finished" :js/rchanges (log-changes (:redo-changes changes) - file)) + ldata)) (rx/concat (rx/of (set-updating-library false) (ntf/hide {:tag :sync-dialog})) @@ -1161,7 +1161,8 @@ (ptk/reify ::ignore-sync ptk/UpdateEvent (update [_ state] - (assoc-in state [:workspace-file :ignore-sync-until] (dt/now))) + (let [file-id (:current-file-id state)] + (assoc-in state [:files file-id :ignore-sync-until] (dt/now)))) ptk/WatchEvent (watch [_ state _] @@ -1175,11 +1176,13 @@ "Get a lazy sequence of all the assets of each type in the library that have been modified after the last sync of the library. The sync date may be overriden by providing a ignore-until parameter." - ([library file-data] (assets-need-sync library file-data nil)) + ([library file-data] + (assets-need-sync library file-data nil)) ([library file-data ignore-until] - (let [sync-date (max (:synced-at library) (or ignore-until 0))] - (when (> (:modified-at library) sync-date) - (ctf/used-assets-changed-since file-data library sync-date))))) + (when (not= (:id library) (:id file-data)) + (let [sync-date (max (:synced-at library) (or ignore-until 0))] + (when (> (:modified-at library) sync-date) + (ctf/used-assets-changed-since file-data library sync-date)))))) (defn notify-sync-file [file-id] @@ -1187,18 +1190,29 @@ (ptk/reify ::notify-sync-file ptk/WatchEvent (watch [_ state _] - (let [file-data (:workspace-data state) - ignore-until (dm/get-in state [:workspace-file :ignore-sync-until]) - libraries-need-sync (filter #(seq (assets-need-sync % file-data ignore-until)) - (vals (get state :libraries))) - do-more-info #(modal/show! :libraries-dialog {:starting-tab "updates"}) - do-update #(do (apply st/emit! (map (fn [library] - (sync-file (:current-file-id state) - (:id library))) - libraries-need-sync)) - (st/emit! (ntf/hide))) - do-dismiss #(do (st/emit! ignore-sync) - (st/emit! (ntf/hide)))] + (let [file (dm/get-in state [:files file-id]) + file-data (get file :data) + ignore-until (get file :ignore-sync-until) + + + ;; FIXME: syntax of this can be improved + libraries-need-sync + (filter #(seq (assets-need-sync % file-data ignore-until)) + (vals (get state :files))) + + do-more-info + #(modal/show! :libraries-dialog {:starting-tab "updates"}) + + do-update + #(do (apply st/emit! (map (fn [library] + (sync-file (:current-file-id state) + (:id library))) + libraries-need-sync)) + (st/emit! (ntf/hide))) + + do-dismiss + #(do (st/emit! ignore-sync) + (st/emit! (ntf/hide)))] (when (seq libraries-need-sync) (rx/of (ntf/dialog @@ -1227,7 +1241,7 @@ ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) + (let [data (dsh/lookup-file-data state) changes (-> (pcb/empty-changes it) (pcb/with-library-data data) (pcb/update-component id #(assoc % :modified-at (dt/now))))] @@ -1351,7 +1365,7 @@ ptk/UpdateEvent (update [_ state] - (assoc-in state [:workspace-file :is-shared] is-shared)) + (update-in state [:files id] assoc :is-shared is-shared)) ptk/WatchEvent (watch [_ _ _] @@ -1377,7 +1391,7 @@ (let [libraries (:workspace-shared-files state) library (d/seek #(= (:id %) library-id) libraries)] (if library - (update state :libraries assoc library-id (dissoc library :library-summary)) + (update state :files assoc library-id (dissoc library :library-summary)) state))) ptk/WatchEvent @@ -1389,9 +1403,10 @@ (rx/ignore)) (->> (rp/cmd! :get-file {:id library-id :features features}) (rx/merge-map fpmap/resolve-file) + ;; FIXME: this should call the libraries-fetched event instead of ad-hoc assoc event (rx/map (fn [file] (fn [state] - (assoc-in state [:libraries library-id] file))))) + (assoc-in state [:files library-id] file))))) (->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"}) (rx/map (fn [thumbnails] (fn [state] @@ -1409,7 +1424,7 @@ ptk/UpdateEvent (update [_ state] - (d/dissoc-in state [:libraries library-id])) + (update state :files dissoc library-id)) ptk/WatchEvent (watch [_ _ _] diff --git a/frontend/src/app/main/data/workspace/media.cljs b/frontend/src/app/main/data/workspace/media.cljs index 8ff1195b6..dfebb5ab6 100644 --- a/frontend/src/app/main/data/workspace/media.cljs +++ b/frontend/src/app/main/data/workspace/media.cljs @@ -21,11 +21,11 @@ [app.common.uuid :as uuid] [app.config :as cf] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.media :as dmm] [app.main.data.notifications :as ntf] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.svg-upload :as svg] [app.main.repo :as rp] [app.main.store :as st] @@ -266,9 +266,11 @@ (on-success image) (dmm/notify-finished-loading)) + file-id (:current-file-id state) + prepare (fn [content] - {:file-id (get-in state [:workspace-file :id]) + {:file-id file-id :name (if (dmm/file? content) (.-name content) (tr "media.image")) :is-local false :content content})] @@ -399,22 +401,31 @@ (ptk/reify ::process-img-component ptk/WatchEvent (watch [it state _] - (let [file-data (wsh/get-local-file state) - page (wsh/lookup-page state) - pos (wsh/viewport-center state)] + (let [file-id (:current-file-id state) + page-id (:current-page-id state) + + fdata (dsh/lookup-file-data state file-id) + page (dsh/get-page fdata page-id) + pos (dsh/get-viewport-center state)] + (->> (create-shapes-img pos media-obj) - (rx/map (partial add-shapes-and-component it file-data page (:name media-obj)))))))) + (rx/map (partial add-shapes-and-component it fdata page (:name media-obj)))))))) (defn- process-svg-component [svg-data] (ptk/reify ::process-svg-component ptk/WatchEvent (watch [it state _] - (let [file-data (wsh/get-local-file state) - page (wsh/lookup-page state) - pos (wsh/viewport-center state)] - (->> (create-shapes-svg (:id file-data) (:objects page) pos svg-data) - (rx/map (partial add-shapes-and-component it file-data page (:name svg-data)))))))) + + (let [file-id (:current-file-id state) + page-id (:current-page-id state) + + fdata (dsh/lookup-file-data state file-id) + page (dsh/get-page fdata page-id) + pos (dsh/get-viewport-center state)] + + (->> (create-shapes-svg file-id (:objects page) pos svg-data) + (rx/map (partial add-shapes-and-component it fdata page (:name svg-data)))))))) (defn upload-media-components [params] diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index c2d75abf6..1049bfc3a 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -23,10 +23,10 @@ [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.constants :refer [zoom-half-pixel-precision]] + [app.main.data.helpers :as dsh] [app.main.data.workspace.comments :as-alias dwcm] [app.main.data.workspace.guides :as-alias dwg] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -335,7 +335,7 @@ ([state ignore-constraints ignore-snap-pixel modif-tree params] (let [objects - (wsh/lookup-page-objects state) + (dsh/lookup-page-objects state) snap-pixel? (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid)) @@ -355,7 +355,7 @@ (defn- calculate-update-modifiers [old-modif-tree state ignore-constraints ignore-snap-pixel modif-tree] (let [objects - (wsh/lookup-page-objects state) + (dsh/lookup-page-objects state) snap-pixel? (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid)) @@ -421,7 +421,7 @@ (ptk/reify ::set-rotation-modifiers ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) ids (sequence xf-rotation-shape shapes) get-modifier @@ -442,7 +442,7 @@ (ptk/reify ::set-delta-rotation-modifiers ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) ids (->> shapes (remove #(get % :blocked false)) @@ -473,7 +473,7 @@ ptk/WatchEvent (watch [_ state _] (let [text-modifiers (get state :workspace-text-modifier) - objects (wsh/lookup-page-objects state) + objects (dsh/lookup-page-objects state) object-modifiers (if (some? modifiers) diff --git a/frontend/src/app/main/data/workspace/notifications.cljs b/frontend/src/app/main/data/workspace/notifications.cljs index e59e7b92b..f5e85bce2 100644 --- a/frontend/src/app/main/data/workspace/notifications.cljs +++ b/frontend/src/app/main/data/workspace/notifications.cljs @@ -13,6 +13,7 @@ [app.common.uuid :as uuid] [app.main.data.changes :as dch] [app.main.data.common :as dc] + [app.main.data.helpers :as dsh] [app.main.data.modal :as modal] [app.main.data.plugins :as dpl] [app.main.data.websocket :as dws] @@ -273,7 +274,7 @@ [:file-id ::sm/uuid] [:vern :int]]) -(def ^:private check-file-restore-params! +(def ^:private check-file-restore-params (sm/check-fn schema:handle-file-restore)) (defn handle-file-restore @@ -281,15 +282,17 @@ (dm/assert! "expected valid parameters" - (check-file-restore-params! msg)) + (check-file-restore-params msg)) (ptk/reify ::handle-file-restore ptk/WatchEvent (watch [_ state _] (let [curr-file-id (:current-file-id state) - curr-vern (dm/get-in state [:workspace-file :vern]) - reload? (and (= file-id curr-file-id) (not= vern curr-vern))] - (when reload? + file (dsh/lookup-file state curr-file-id) + curr-vern (:vern file)] + + (when (and (= file-id curr-file-id) + (not= vern curr-vern)) (rx/of (ptk/event ::dw/reload-current-file))))))) (def ^:private schema:handle-library-change diff --git a/frontend/src/app/main/data/workspace/path/changes.cljs b/frontend/src/app/main/data/workspace/path/changes.cljs index 43ad6fdc0..547500698 100644 --- a/frontend/src/app/main/data/workspace/path/changes.cljs +++ b/frontend/src/app/main/data/workspace/path/changes.cljs @@ -9,10 +9,10 @@ [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.workspace.path.common :refer [check-path-content!]] [app.main.data.workspace.path.helpers :as helpers] [app.main.data.workspace.path.state :as st] - [app.main.data.workspace.state-helpers :as wsh] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -83,7 +83,7 @@ ptk/WatchEvent (watch [it state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) page-id (:current-page-id state) id (get-in state [:workspace-local :edition]) old-content (get-in state [:workspace-local :edit-path id :old-content]) diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index 9b562723e..631c28d32 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -15,6 +15,7 @@ [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.types.shape.layout :as ctl] + [app.main.data.helpers :as dsh] [app.main.data.workspace.drawing.common :as dwdc] [app.main.data.workspace.edition :as dwe] [app.main.data.workspace.path.changes :as changes] @@ -24,7 +25,6 @@ [app.main.data.workspace.path.streams :as streams] [app.main.data.workspace.path.undo :as undo] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.util.mouse :as mse] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -252,7 +252,7 @@ (ptk/reify ::setup-frame ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) content (get-in state [:workspace-drawing :object :content] []) position (gpt/point (get-in content [0 :params] nil)) frame-id (->> (ctst/top-nested-frame objects position) @@ -321,11 +321,10 @@ (ptk/reify ::start-draw-mode ptk/UpdateEvent (update [_ state] - (let [id (get-in state [:workspace-local :edition]) - page-id (:current-page-id state) - old-content (get-in state [:workspace-data :pages-index page-id :objects id :content])] - (-> state - (assoc-in [:workspace-local :edit-path id :old-content] old-content)))) + (let [id (dm/get-in state [:workspace-local :edition]) + objects (dsh/lookup-page-objects state) + content (dm/get-in objects [id :content])] + (update-in state [:workspace-local :edit-path id] assoc :old-content content))) ptk/WatchEvent (watch [_ state stream] diff --git a/frontend/src/app/main/data/workspace/path/edition.cljs b/frontend/src/app/main/data/workspace/path/edition.cljs index 36af8c593..a4cdf6f6d 100644 --- a/frontend/src/app/main/data/workspace/path/edition.cljs +++ b/frontend/src/app/main/data/workspace/path/edition.cljs @@ -15,6 +15,7 @@ [app.common.svg.path.shapes-to-path :as upsp] [app.common.svg.path.subpath :as ups] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.workspace.edition :as dwe] [app.main.data.workspace.path.changes :as changes] [app.main.data.workspace.path.drawing :as drawing] @@ -24,7 +25,6 @@ [app.main.data.workspace.path.streams :as streams] [app.main.data.workspace.path.undo :as undo] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.streams :as ms] [app.util.mouse :as mse] [app.util.path.tools :as upt] @@ -50,7 +50,7 @@ (ptk/reify ::apply-content-modifiers ptk/WatchEvent (watch [it state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) id (st/get-path-id state) page-id (:current-page-id state) @@ -294,7 +294,7 @@ (ptk/reify ::start-path-edit ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) edit-path (dm/get-in state [:workspace-local :edit-path id]) content (st/get-path state :content) state (cond-> state diff --git a/frontend/src/app/main/data/workspace/path/shapes_to_path.cljs b/frontend/src/app/main/data/workspace/path/shapes_to_path.cljs index e916aec62..e26930528 100644 --- a/frontend/src/app/main/data/workspace/path/shapes_to_path.cljs +++ b/frontend/src/app/main/data/workspace/path/shapes_to_path.cljs @@ -11,7 +11,7 @@ [app.common.svg.path.shapes-to-path :as upsp] [app.common.types.container :as ctn] [app.main.data.changes :as dch] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -23,8 +23,8 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state) - selected (->> (or ids (wsh/lookup-selected state)) + objects (dsh/lookup-page-objects state) + selected (->> (or ids (dsh/lookup-selected state)) (remove #(ctn/has-any-copy-parent? objects (get objects %)))) children-ids diff --git a/frontend/src/app/main/data/workspace/path/state.cljs b/frontend/src/app/main/data/workspace/path/state.cljs index 77d3e42cb..0a6deb186 100644 --- a/frontend/src/app/main/data/workspace/path/state.cljs +++ b/frontend/src/app/main/data/workspace/path/state.cljs @@ -51,22 +51,20 @@ (defn get-path-location [state & ks] - (let [edit-id (get-in state [:workspace-local :edition]) - page-id (:current-page-id state)] - (into (if edit-id - [:workspace-data :pages-index page-id :objects edit-id] - [:workspace-drawing :object]) - ks))) + (if-let [edit-id (dm/get-in state [:workspace-local :edition])] + (let [page-id (:current-page-id state) + file-id (:current-file-id state)] + (into [:files file-id :data :pages-index page-id :objects edit-id] ks)) + (into [:workspace-drawing :object] ks))) (defn get-path "Retrieves the location of the path object and additionally can pass the arguments. This location can be used in get-in, assoc-in... functions" [state & ks] (let [path-loc (get-path-location state) - shape (-> (get-in state path-loc) - ;; Empty map because we know the current shape will not have children - (upsp/convert-to-path {}))] - + shape (-> (get-in state path-loc) + ;; Empty map because we know the current shape will not have children + (upsp/convert-to-path {}))] (if (empty? ks) shape (get-in shape ks)))) @@ -74,5 +72,4 @@ (defn set-content [state content] (let [path-loc (get-path-location state :content)] - (-> state - (assoc-in path-loc content)))) + (assoc-in state path-loc content))) diff --git a/frontend/src/app/main/data/workspace/path/tools.cljs b/frontend/src/app/main/data/workspace/path/tools.cljs index 0c17182c3..df495c1b2 100644 --- a/frontend/src/app/main/data/workspace/path/tools.cljs +++ b/frontend/src/app/main/data/workspace/path/tools.cljs @@ -9,11 +9,11 @@ [app.common.svg.path.shapes-to-path :as upsp] [app.common.svg.path.subpath :as ups] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.workspace.edition :as dwe] [app.main.data.workspace.path.changes :as changes] [app.main.data.workspace.path.state :as st] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.util.path.tools :as upt] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -26,7 +26,7 @@ (ptk/reify ::process-path-tool ptk/WatchEvent (watch [it state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) id (st/get-path-id state) page-id (:current-page-id state) shape (st/get-path state) diff --git a/frontend/src/app/main/data/workspace/path/undo.cljs b/frontend/src/app/main/data/workspace/path/undo.cljs index bdaa7e256..54b2f3eea 100644 --- a/frontend/src/app/main/data/workspace/path/undo.cljs +++ b/frontend/src/app/main/data/workspace/path/undo.cljs @@ -132,8 +132,9 @@ dissoc :undo-lock :undo-stack))))) (defn- stop-undo? [event] - (or (= :app.main.data.workspace.common/clear-edition-mode (ptk/type event)) - (= :app.main.data.workspace/finalize-page (ptk/type event)))) + (let [type (ptk/type event)] + (or (= :app.main.data.workspace.edition/clear-edition-mode type) + (= :app.main.data.workspace/finalize-page type)))) (def path-content-ref (letfn [(selector [state] diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 3ce38f67d..d92bfd4a6 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -19,10 +19,10 @@ [app.common.uuid :as uuid] [app.main.data.changes :as dch] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.modal :as md] [app.main.data.workspace.collapse :as dwc] [app.main.data.workspace.specialized-panel :as-alias dwsp] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.data.workspace.zoom :as dwz] [app.main.refs :as refs] @@ -140,9 +140,9 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected-id (wsh/lookup-selected state) - selected (wsh/lookup-shapes state selected-id) + objects (dsh/lookup-page-objects state page-id) + selected-id (dsh/lookup-selected state) + selected (dsh/lookup-shapes state selected-id) frame-ids (map (fn [item] (let [parent (cfh/get-frame objects (:id item))] (:id parent))) selected) params-without-board (-> (rt/get-params state) @@ -162,11 +162,11 @@ (ptk/reify ::select-prev-shape ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) + (let [selected (dsh/lookup-selected state) count-selected (count selected) first-selected (first selected) page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) current (get objects first-selected) parent (get objects (:parent-id current)) sibling-ids (:shapes parent) @@ -187,11 +187,11 @@ (ptk/reify ::select-next-shape ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) + (let [selected (dsh/lookup-selected state) count-selected (count selected) first-selected (first selected) page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) current (get objects first-selected) parent (get objects (:parent-id current)) sibling-ids (:shapes parent) @@ -230,10 +230,10 @@ (rx/of ::dwsp/interrupt)) ptk/UpdateEvent (update [_ state] - (let [objects (or objects (wsh/lookup-page-objects state)) + (let [objects (or objects (dsh/lookup-page-objects state)) append-to-selection (cfh/expand-region-selection objects (into #{} [(get-in state [:workspace-local :last-selected]) id])) selection (-> state - wsh/lookup-selected + dsh/lookup-selected (conj id))] (-> state (assoc-in [:workspace-local :selected] @@ -250,7 +250,7 @@ (ptk/reify ::select-shapes ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) focus (:workspace-focus-selected state) ids (if (d/not-empty? focus) (cpf/filter-not-focus objects focus ids) @@ -259,7 +259,7 @@ ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state)] + (let [objects (dsh/lookup-page-objects state)] (rx/of (dwc/expand-all-parents ids objects) ::dwsp/interrupt))))) @@ -273,11 +273,11 @@ ;; case delimit the objects to the focused shapes if focus ;; mode is active focus (:workspace-focus-selected state) - objects (-> (wsh/lookup-page-objects state) + objects (-> (dsh/lookup-page-objects state) (cpf/focus-objects focus)) lookup (d/getf objects) - parents (->> (wsh/lookup-selected state) + parents (->> (dsh/lookup-selected state) (into #{} (comp (keep lookup) (map :parent-id)))) ;; If we have a only unique parent, then use it as main @@ -307,6 +307,7 @@ (dissoc :board-id))] (rx/of ::dwsp/interrupt) (rx/of (rt/nav :workspace params-without-board {::rt/replace true})))) + ptk/UpdateEvent (update [_ state] @@ -329,8 +330,8 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state) - selected (wsh/lookup-selected state) + objects (dsh/lookup-page-objects state) + selected (dsh/lookup-selected state) initial-set (if preserve? selected lks/empty-linked-set) @@ -363,7 +364,7 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) group (get objects group-id) children (map #(get objects %) (:shapes group)) @@ -435,7 +436,7 @@ (ptk/reify ::duplicate-shapes ptk/WatchEvent (watch [it state _] - (let [page (wsh/lookup-page state) + (let [page (dsh/lookup-page state) objects (:objects page) ids (into #{} (comp (map (d/getf objects)) @@ -449,8 +450,9 @@ (gpt/point 0 0)) file-id (:current-file-id state) - libraries (wsh/get-libraries state) - library-data (wsh/get-file state file-id) + + libraries (dsh/lookup-libraries state) + library-data (dsh/lookup-file-data state file-id) changes (-> (pcb/empty-changes it) (cll/generate-duplicate-changes objects page ids delta libraries library-data file-id) @@ -504,7 +506,7 @@ ptk/WatchEvent (watch [_ state _] (when (or (not move-delta?) (nil? (get-in state [:workspace-local :transform]))) - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (rx/of (duplicate-shapes selected :move-delta? move-delta? :alt-duplication? alt-duplication?)))))))) @@ -523,7 +525,7 @@ ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) focus (-> (:workspace-focus-selected state) (set/union added) @@ -541,7 +543,7 @@ ptk/UpdateEvent (update [_ state] - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (cond-> state (and (empty? (:workspace-focus-selected state)) (d/not-empty? selected)) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index e910fafec..6f3bd016c 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -22,12 +22,12 @@ [app.common.uuid :as uuid] [app.main.data.changes :as dch] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.workspace.colors :as cl] [app.main.data.workspace.grid-layout.editor :as dwge] [app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.selection :as dwse] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -101,7 +101,7 @@ (ptk/reify ::update-layout-positions ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) ids (->> ids (filter #(contains? objects %)))] (if (d/not-empty? ids) (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] @@ -144,7 +144,7 @@ (ptk/reify ::create-layout-from-id ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) parent (get objects id) undo-id (js/Symbol) layout-initializer (get-layout-initializer type from-frame? calculate-params?)] @@ -162,8 +162,8 @@ (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (wsh/lookup-selected state) + objects (dsh/lookup-page-objects state page-id) + selected (dsh/lookup-selected state) selected-shapes (map (d/getf objects) selected) single? (= (count selected-shapes) 1) has-group? (->> selected-shapes (d/seek cfh/group-shape?)) @@ -229,8 +229,8 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (wsh/lookup-selected state) + objects (dsh/lookup-page-objects state page-id) + selected (dsh/lookup-selected state) selected-shapes (map (d/getf objects) selected) single? (= (count selected-shapes) 1) is-frame? (= :frame (:type (first selected-shapes))) @@ -248,8 +248,8 @@ (ptk/reify ::toggle-shape-layout ptk/WatchEvent (watch [it state _] - (let [objects (wsh/lookup-page-objects state) - selected (wsh/lookup-selected state) + (let [objects (dsh/lookup-page-objects state) + selected (dsh/lookup-selected state) selected-shapes (map (d/getf objects) selected) single? (= (count selected-shapes) 1) has-layout? (and single? @@ -300,7 +300,7 @@ ptk/WatchEvent (watch [_ state _] (let [undo-id (js/Symbol)] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shapes-to-delete (when with-shapes? @@ -334,10 +334,10 @@ ptk/WatchEvent (watch [it state _] (let [file-id (:current-file-id state) - page (wsh/lookup-page state) + page (dsh/lookup-page state) objects (:objects page) - libraries (wsh/get-libraries state) - library-data (wsh/get-file state file-id) + libraries (dsh/lookup-libraries state) + library-data (dsh/lookup-file state file-id) shape-id (first ids) base-shape (get objects shape-id) @@ -406,7 +406,7 @@ (ptk/reify ::hover-layout-track ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects (first ids)) highlighted @@ -524,7 +524,7 @@ (ptk/reify ::update-layout-child ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) children-ids (->> ids (mapcat #(cfh/get-children-ids objects %))) parent-ids (->> ids (map #(cfh/get-parent-id objects %))) undo-id (js/Symbol)] @@ -694,7 +694,7 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state) + objects (dsh/lookup-page-objects state) frame-id (uuid/next) undo-id (js/Symbol) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 3433c6a1c..fd2e13b2d 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -19,9 +19,9 @@ [app.main.data.changes :as dch] [app.main.data.comments :as dc] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.workspace.edition :as dwe] [app.main.data.workspace.selection :as dws] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.features :as features] [beicon.v2.core :as rx] @@ -60,7 +60,7 @@ ptk/WatchEvent (watch [it state _] (let [page-id (or page-id (:current-page-id state)) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) ids (into [] (filter some?) ids) update-layout-ids @@ -107,7 +107,7 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) [shape changes] (-> (pcb/empty-changes it page-id) @@ -140,7 +140,7 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shapes (->> shapes (remove #(dm/get-in objects [% :blocked])) (cfh/order-by-indexed-shapes objects)) @@ -169,16 +169,19 @@ (watch [it state _] (let [file-id (:current-file-id state) page-id (or page-id (:current-page-id state)) - file (wsh/get-file state file-id) - page (wsh/lookup-page state page-id) - objects (wsh/lookup-page-objects state page-id) + + fdata (dsh/lookup-file-data state file-id) + page (dsh/get-page fdata page-id) + objects (:objects page) + components-v2 (features/active-feature? state "components/v2") undo-id (or (:undo-id options) (js/Symbol)) [all-parents changes] (-> (pcb/empty-changes it (:id page)) - (cls/generate-delete-shapes file page objects ids {:components-v2 components-v2 - :ignore-touched (:component-swap options) - :undo-group (:undo-group options) - :undo-id undo-id}))] + (cls/generate-delete-shapes fdata page objects ids + {:components-v2 components-v2 + :ignore-touched (:component-swap options) + :undo-group (:undo-group options) + :undo-id undo-id}))] (rx/of (dwu/start-undo-transaction undo-id) (dc/detach-comment-thread ids) @@ -191,15 +194,15 @@ (ptk/reify ::create-and-add-shape ptk/WatchEvent (watch [_ state _] - (let [vbc (wsh/viewport-center state) + (let [vbc (dsh/get-viewport-center state) x (:x attrs (- (:x vbc) (/ width 2))) y (:y attrs (- (:y vbc) (/ height 2))) page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - frame-id (-> (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) + frame-id (-> (dsh/lookup-page-objects state page-id) (ctst/top-nested-frame {:x frame-x :y frame-y})) - selected (wsh/lookup-selected state) + selected (dsh/lookup-selected state) base (cfh/get-base-shape objects selected) parent-id (if (or (and (= 1 (count selected)) @@ -241,8 +244,8 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (->> (wsh/lookup-selected state) + objects (dsh/lookup-page-objects state page-id) + selected (->> (dsh/lookup-selected state) (cfh/clean-loops objects) (remove #(ctn/has-any-copy-parent? objects (get objects %)))) @@ -291,7 +294,7 @@ (cond-> obj (boolean? blocked) (assoc :blocked blocked) (boolean? hidden) (assoc :hidden hidden))) - objects (wsh/lookup-page-objects state) + objects (dsh/lookup-page-objects state) ;; We have change only the hidden behaviour, to hide only the ;; selected shape, block behaviour remains the same. ids (if (boolean? blocked) @@ -304,7 +307,7 @@ (ptk/reify ::toggle-visibility-selected ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (rx/of (update-shapes selected #(update % :hidden not))))))) (defn toggle-lock-selected @@ -312,7 +315,7 @@ (ptk/reify ::toggle-lock-selected ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (rx/of (update-shapes selected #(update % :blocked not))))))) @@ -323,8 +326,9 @@ (ptk/reify ::toggle-file-thumbnail-selected ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) - pages (-> state :workspace-data :pages-index vals) + (let [selected (dsh/lookup-selected state) + fdata (dsh/lookup-file-data state) + pages (-> fdata :pages-index vals) undo-id (js/Symbol)] (rx/concat diff --git a/frontend/src/app/main/data/workspace/specialized_panel.cljs b/frontend/src/app/main/data/workspace/specialized_panel.cljs index eb4ec08f5..58cb18058 100644 --- a/frontend/src/app/main/data/workspace/specialized_panel.cljs +++ b/frontend/src/app/main/data/workspace/specialized_panel.cljs @@ -7,8 +7,8 @@ (ns app.main.data.workspace.specialized-panel (:require [app.common.data :as d] + [app.main.data.helpers :as dsh] [app.main.data.workspace.common :as-alias dwc] - [app.main.data.workspace.state-helpers :as wsh] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -28,8 +28,8 @@ ptk/UpdateEvent (update [_ state] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected-ids (wsh/lookup-selected state) + objects (dsh/lookup-page-objects state page-id) + selected-ids (dsh/lookup-selected state) selected-shapes (map (d/getf objects) selected-ids)] (assoc state :specialized-panel {:type type :shapes selected-shapes}))) ptk/WatchEvent diff --git a/frontend/src/app/main/data/workspace/state_helpers.cljs b/frontend/src/app/main/data/workspace/state_helpers.cljs deleted file mode 100644 index eefcb7428..000000000 --- a/frontend/src/app/main/data/workspace/state_helpers.cljs +++ /dev/null @@ -1,168 +0,0 @@ -;; 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.workspace.state-helpers - (:require - [app.common.data :as d] - [app.common.data.macros :as dm] - [app.common.files.helpers :as cfh] - [app.common.geom.point :as gpt] - [app.common.geom.shapes :as gsh] - [app.common.svg.path.command :as upc] - [app.common.uuid :as uuid])) - -(defn lookup-page - ([state] - (lookup-page state (:current-page-id state))) - ([state page-id] - (get-in state [:workspace-data :pages-index page-id]))) - -(defn lookup-page-objects - ([state] - (lookup-page-objects state (:current-page-id state))) - ([state page-id] - (-> (lookup-page state page-id) - (get :objects)))) - -(defn lookup-library-objects - [state file-id page-id] - (dm/get-in state [:libraries file-id :data :pages-index page-id :objects])) - -(defn lookup-objects - [state file-id page-id] - (let [current-file? (= file-id (:current-file-id state))] - (if ^boolean current-file? - (lookup-page-objects state page-id) - (lookup-library-objects state file-id page-id)))) - -(defn lookup-local-components - ([state] - (dm/get-in state [:workspace-data :components]))) - -(defn process-selected-shapes - ([objects selected] - (process-selected-shapes objects selected nil)) - - ([objects selected {:keys [omit-blocked?] :or {omit-blocked? false}}] - (letfn [(selectable? [id] - (and (contains? objects id) - (or (not omit-blocked?) - (not (get-in objects [id :blocked] false)))))] - (let [selected (->> selected (cfh/clean-loops objects))] - (into (d/ordered-set) - (filter selectable?) - selected))))) - -(defn lookup-selected-raw - [state] - (dm/get-in state [:workspace-local :selected])) - -(defn lookup-selected - ([state] - (lookup-selected state nil)) - ([state options] - (lookup-selected state (:current-page-id state) options)) - ([state page-id options] - (let [objects (lookup-page-objects state page-id) - selected (dm/get-in state [:workspace-local :selected])] - (process-selected-shapes objects selected options)))) - -(defn lookup-shape - ([state id] - (lookup-shape state (:current-page-id state) id)) - - ([state page-id id] - (let [objects (lookup-page-objects state page-id)] - (get objects id)))) - -(defn lookup-shapes - ([state ids] - (lookup-shapes state (:current-page-id state) ids)) - ([state page-id ids] - (let [objects (lookup-page-objects state page-id)] - (into [] (keep (d/getf objects)) ids)))) - -(defn filter-shapes - ([state filter-fn] - (filter-shapes state (:current-page-id state) filter-fn)) - ([state page-id filter-fn] - (let [objects (lookup-page-objects state page-id)] - (into [] (filter filter-fn) (vals objects))))) - -(defn get-local-file - "Get the data content of the file you are currently working with." - [state] - (get state :workspace-data)) - -(defn get-local-file-full - [state] - (-> (get state :workspace-file) - (assoc :data (get state :workspace-data)))) - -(defn get-file - "Get the data content of the given file (it may be the current file - or one library)." - [state file-id] - (if (= file-id (:current-file-id state)) - (get state :workspace-data) - (dm/get-in state [:libraries file-id :data]))) - -(defn get-file-full - "Get the data content of the given file (it may be the current file - or one library)." - [state file-id] - (if (= file-id (:current-file-id state)) - (-> (get state :workspace-file) - (assoc :data (get state :workspace-data))) - (dm/get-in state [:libraries file-id :data]))) - -(defn get-libraries - "Retrieve all libraries, including the local file." - [state] - (let [{:keys [id] :as local} (:workspace-data state)] - (-> (:libraries state) - (assoc id {:id id - :data local})))) - -(defn- set-content-modifiers [state] - (fn [id shape] - (let [content-modifiers (dm/get-in state [:workspace-local :edit-path id :content-modifiers])] - (if (some? content-modifiers) - (update shape :content upc/apply-content-modifiers content-modifiers) - shape)))) - -(defn select-bool-children - [parent-id state] - (let [objects (lookup-page-objects state) - modifiers (:workspace-modifiers state) - children-ids (cfh/get-children-ids objects parent-id) - children - (-> (select-keys objects children-ids) - (update-vals - (fn [child] - (cond-> child - (contains? modifiers (:id child)) - (gsh/transform-shape (get-in modifiers [(:id child) :modifiers]))))))] - - (as-> children $ - (d/mapm (set-content-modifiers state) $)))) - -(defn viewport-center - [state] - (let [{:keys [x y width height]} (get-in state [:workspace-local :vbox])] - (gpt/point (+ x (/ width 2)) (+ y (/ height 2))))) - -(defn find-orphan-shapes - ([state] - (find-orphan-shapes state (:current-page-id state))) - ([state page-id] - (let [objects (lookup-page-objects state page-id) - objects (filter (fn [item] - (and - (not= (key item) uuid/zero) - (not (contains? objects (:parent-id (val item)))))) - objects)] - objects))) diff --git a/frontend/src/app/main/data/workspace/svg_upload.cljs b/frontend/src/app/main/data/workspace/svg_upload.cljs index 6f04e7c66..8374a9c41 100644 --- a/frontend/src/app/main/data/workspace/svg_upload.cljs +++ b/frontend/src/app/main/data/workspace/svg_upload.cljs @@ -15,8 +15,8 @@ [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.workspace.selection :as dws] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.repo :as rp] [app.util.webapi :as wapi] @@ -72,8 +72,8 @@ (try (let [id (d/nilv id (uuid/next)) page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (if ignore-selection? #{} (wsh/lookup-selected state)) + objects (dsh/lookup-page-objects state page-id) + selected (if ignore-selection? #{} (dsh/lookup-selected state)) base (cfh/get-base-shape objects selected) selected-id (first selected) diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index b0c69130e..f8a3399ce 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -18,12 +18,12 @@ [app.common.types.modifiers :as ctm] [app.common.uuid :as uuid] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.workspace.common :as dwc] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.features :as features] [app.main.fonts :as fonts] @@ -89,7 +89,7 @@ ptk/WatchEvent (watch [_ state _] (when (dwc/initialized? state) - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects id) editor-state (get-in state [:workspace-editor-state id]) content (-> editor-state @@ -321,7 +321,7 @@ (ptk/reify ::update-text-range ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects id) update-fn @@ -347,7 +347,7 @@ (ptk/reify ::update-root-attrs ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects id) update-fn @@ -372,7 +372,7 @@ ptk/WatchEvent (watch [_ state _] (when-not (some? (get-in state [:workspace-editor-state id])) - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects id) merge-fn (fn [node attrs] @@ -398,7 +398,7 @@ ptk/WatchEvent (watch [_ state _] (when-not (some? (get-in state [:workspace-editor-state id])) - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects id) update-node? (fn [node] (or (txt/is-text-node? node) @@ -446,9 +446,8 @@ (when (or (and (features/active-feature? state "text-editor/v2") (nil? (:workspace-editor state))) (and (not (features/active-feature? state "text-editor/v2")) (nil? (get-in state [:workspace-editor-state id])))) - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects id) - update-node? (some-fn txt/is-text-node? txt/is-paragraph-node?) shape-ids @@ -485,8 +484,8 @@ (ptk/reify ::start-edit-if-selected ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) - selected (->> state wsh/lookup-selected (mapv #(get objects %)))] + (let [objects (dsh/lookup-page-objects state) + selected (->> state dsh/lookup-selected (mapv #(get objects %)))] (cond-> state (and (= 1 (count selected)) (= (-> selected first :type) :text)) @@ -501,7 +500,7 @@ ptk/WatchEvent (watch [_ state _] (let [props (::resize-text-debounce-props state) - objects (wsh/lookup-page-objects state) + objects (dsh/lookup-page-objects state) undo-id (js/Symbol)] (letfn [(changed-text? [id] @@ -765,7 +764,7 @@ ptk/WatchEvent (watch [_ state _] (let [editor-state (:workspace-editor-state state) - ids (d/nilv ids (wsh/lookup-selected state)) + ids (d/nilv ids (dsh/lookup-selected state)) attrs (-> typography (assoc :typography-ref-file file-id) (assoc :typography-ref-id (:id typography)) @@ -794,8 +793,8 @@ (ptk/reify ::add-typography ptk/WatchEvent (watch [_ state _] - (let [selected (wsh/lookup-selected state) - objects (wsh/lookup-page-objects state) + (let [selected (dsh/lookup-selected state) + objects (dsh/lookup-page-objects state) xform (comp (keep (d/getf objects)) (filter cfh/text-shape?)) @@ -863,7 +862,7 @@ (ptk/reify ::v2-update-text-shape-content ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shape (get objects id) modifiers (get-in state [:workspace-text-modifier id]) new-shape? (nil? (:content shape))] diff --git a/frontend/src/app/main/data/workspace/thumbnails.cljs b/frontend/src/app/main/data/workspace/thumbnails.cljs index 132db9156..28d81a781 100644 --- a/frontend/src/app/main/data/workspace/thumbnails.cljs +++ b/frontend/src/app/main/data/workspace/thumbnails.cljs @@ -12,9 +12,9 @@ [app.common.thumbnails :as thc] [app.common.uuid :as uuid] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.persistence :as-alias dps] [app.main.data.workspace.notifications :as-alias wnt] - [app.main.data.workspace.state-helpers :as wsh] [app.main.rasterizer :as thr] [app.main.refs :as refs] [app.main.render :as render] @@ -65,7 +65,9 @@ [state file-id page-id frame-id tag] (let [object-id (thc/fmt-object-id file-id page-id frame-id tag) tp (tp/tpoint-ms) - objects (wsh/lookup-objects state file-id page-id) + objects (-> (dsh/lookup-file state file-id) + (dsh/get-page page-id) + :objects) shape (get objects frame-id)] (->> (render/render-frame objects shape object-id) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 3c157498f..cef8b1dae 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -26,10 +26,10 @@ [app.common.types.shape-tree :as ctst] [app.common.types.shape.layout :as ctl] [app.main.data.changes :as dch] + [app.main.data.helpers :as dsh] [app.main.data.workspace.collapse :as dwc] [app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.selection :as dws] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.snap :as snap] [app.main.streams :as ms] @@ -262,7 +262,7 @@ page-id (:current-page-id state) focus (:workspace-focus-selected state) zoom (dm/get-in state [:workspace-local :zoom] 1) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shapes (map (d/getf objects) ids)] (rx/concat @@ -313,10 +313,9 @@ (ptk/reify ::update-dimensions ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) get-modifier (fn [shape] (ctm/change-dimensions-modifiers shape attr value)) - modif-tree (-> (dwm/build-modif-tree ids objects get-modifier) (gm/set-objects-modifiers objects))] @@ -341,7 +340,7 @@ (ptk/reify ::change-orientation ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) get-modifier (fn [shape] (ctm/change-orientation-modifiers shape orientation)) @@ -408,7 +407,7 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shapes (->> ids (map #(get objects %)))] (rx/concat (rx/of (dwm/set-delta-rotation-modifiers rotation shapes params)) @@ -438,7 +437,7 @@ ;; We toggle the selection so we don't have to wait for the event selected - (cond-> (wsh/lookup-selected state {:omit-blocked? true}) + (cond-> (dsh/lookup-selected state {:omit-blocked? true}) (some? id) (d/toggle-selection id shift?))] @@ -502,8 +501,8 @@ ptk/WatchEvent (watch [_ state stream] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (wsh/lookup-selected state {:omit-blocked? true}) + objects (dsh/lookup-page-objects state page-id) + selected (dsh/lookup-selected state {:omit-blocked? true}) ids (if (nil? ids) selected ids) shapes (into [] (comp (map (d/getf objects)) @@ -625,8 +624,8 @@ (ptk/reify ::reorder-layout-child ptk/WatchEvent (watch [it state _] - (let [selected (wsh/lookup-selected state {:omit-blocked? true}) - objects (wsh/lookup-page-objects state) + (let [selected (dsh/lookup-selected state {:omit-blocked? true}) + objects (dsh/lookup-page-objects state) page-id (:current-page-id state) get-move-to-index @@ -734,7 +733,7 @@ ptk/WatchEvent (watch [_ state stream] (if (= same-event (get state ::current-move-selected)) - (let [selected (wsh/lookup-selected state {:omit-blocked? true}) + (let [selected (dsh/lookup-selected state {:omit-blocked? true}) nudge (get-in state [:profile :props :nudge] {:big 10 :small 1}) move-events (->> stream (rx/filter (ptk/type? ::nudge-selected-shapes)) @@ -776,8 +775,8 @@ (ptk/reify ::move-selected ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (wsh/lookup-selected state {:omit-blocked? true}) + (let [objects (dsh/lookup-page-objects state) + selected (dsh/lookup-selected state {:omit-blocked? true}) selected-shapes (->> selected (map (d/getf objects)))] (if (every? #(and (ctl/any-layout-immediate-child? objects %) (not (ctl/position-absolute? %))) @@ -794,7 +793,7 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shape (get objects id) ;; FIXME: performance rect @@ -817,7 +816,7 @@ (ptk/reify ::position-shapes ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) shapes (d/index-by :id shapes) modif-tree @@ -864,7 +863,7 @@ ptk/WatchEvent (watch [it state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) ids (cleanup-invalid-moving-shapes ids objects frame-id) changes (cls/generate-relocate (pcb/empty-changes it) objects @@ -898,8 +897,8 @@ (ptk/reify ::flip-horizontal-selected ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (or ids (wsh/lookup-selected state {:omit-blocked? true})) + (let [objects (dsh/lookup-page-objects state) + selected (or ids (dsh/lookup-selected state {:omit-blocked? true})) shapes (map #(get objects %) selected) selrect (gsh/shapes->rect shapes) center (grc/rect->center selrect) @@ -913,8 +912,8 @@ (ptk/reify ::flip-vertical-selected ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (or ids (wsh/lookup-selected state {:omit-blocked? true})) + (let [objects (dsh/lookup-page-objects state) + selected (or ids (dsh/lookup-selected state {:omit-blocked? true})) shapes (map #(get objects %) selected) selrect (gsh/shapes->rect shapes) center (grc/rect->center selrect) diff --git a/frontend/src/app/main/data/workspace/undo.cljs b/frontend/src/app/main/data/workspace/undo.cljs index 2df61c5e5..52a8f68af 100644 --- a/frontend/src/app/main/data/workspace/undo.cljs +++ b/frontend/src/app/main/data/workspace/undo.cljs @@ -14,7 +14,7 @@ [app.common.types.shape.layout :as ctl] [app.main.data.changes :as dch] [app.main.data.common :as dcm] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [app.util.time :as dt] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -186,7 +186,7 @@ (ptk/reify ::undo-to-index ptk/WatchEvent (watch [it state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) edition (get-in state [:workspace-local :edition]) drawing (get state :workspace-drawing)] (when-not (and (or (some? edition) (some? (:object drawing))) @@ -219,7 +219,7 @@ (ptk/reify ::undo ptk/WatchEvent (watch [it state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) edition (get-in state [:workspace-local :edition]) drawing (get state :workspace-drawing)] @@ -257,7 +257,7 @@ (ptk/reify ::redo ptk/WatchEvent (watch [it state _] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) edition (get-in state [:workspace-local :edition]) drawing (get state :workspace-drawing)] (when (and (or (nil? edition) (ctl/grid-layout? objects edition)) @@ -291,7 +291,8 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - pages (dm/get-in state [:workspace-data :pages])] + pages (-> (dsh/lookup-file-data state) + (get :pages))] (if (contains? pages page-id) (rx/empty) (rx/of (dcm/go-to-workspace :page-id (first pages)))))))) diff --git a/frontend/src/app/main/data/workspace/viewport.cljs b/frontend/src/app/main/data/workspace/viewport.cljs index 12c1f407c..190440811 100644 --- a/frontend/src/app/main/data/workspace/viewport.cljs +++ b/frontend/src/app/main/data/workspace/viewport.cljs @@ -13,7 +13,7 @@ [app.common.geom.rect :as gpr] [app.common.geom.shapes :as gsh] [app.common.math :as mth] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [app.util.mouse :as mse] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -38,7 +38,7 @@ (initialize [state local] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shapes (cfh/get-immediate-children objects) srect (gsh/shapes->rect shapes) local (assoc local :vport size :zoom 1 :zoom-inverse 1 :hide-toolbar false)] diff --git a/frontend/src/app/main/data/workspace/zoom.cljs b/frontend/src/app/main/data/workspace/zoom.cljs index 6499f93a2..98344ba52 100644 --- a/frontend/src/app/main/data/workspace/zoom.cljs +++ b/frontend/src/app/main/data/workspace/zoom.cljs @@ -14,7 +14,7 @@ [app.common.geom.point :as gpt] [app.common.geom.rect :as grc] [app.common.geom.shapes :as gsh] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [app.main.streams :as ms] [app.util.mouse :as mse] [beicon.v2.core :as rx] @@ -83,7 +83,7 @@ ptk/UpdateEvent (update [_ state] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) shapes (cfh/get-immediate-children objects) srect (gsh/shapes->rect shapes)] (if (empty? shapes) @@ -101,11 +101,11 @@ (ptk/reify ::zoom-to-selected-shape ptk/UpdateEvent (update [_ state] - (let [selected (wsh/lookup-selected state)] + (let [selected (dsh/lookup-selected state)] (if (empty? selected) state (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) srect (->> selected (map #(get objects %)) (gsh/shapes->rect))] @@ -126,7 +126,7 @@ (if (empty? ids) state (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) srect (->> ids (map #(get objects %)) (gsh/shapes->rect))] diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index e87a6370b..a5007a143 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -14,7 +14,7 @@ [app.common.types.shape.layout :as ctl] [app.common.types.tokens-lib :as ctob] [app.config :as cf] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [app.main.store :as st] [app.main.ui.workspace.tokens.token-set :as wtts] [okulary.core :as l])) @@ -53,7 +53,7 @@ (def exception (l/derived :exception st/state)) -(def threads-ref +(def threads (l/derived :comment-threads st/state)) (def share-links @@ -71,13 +71,22 @@ (def files (l/derived :files st/state)) +(def file + (l/derived (fn [state] + (let [file-id (:current-file-id state) + files (:files state)] + (get files file-id))) + st/state)) + (def shared-files "A derived state that points to the current list of shared files (without the content, only summary)" (l/derived :shared-files st/state)) (def libraries - (l/derived :libraries st/state)) + "A derived state that contanins the currently loaded shared libraries + with all its content; including the current file" + (l/derived :files st/state)) (defn extract-selected-files [files selected] @@ -121,7 +130,7 @@ (def ^:private selected-shapes-data (l/derived (fn [state] - (let [objects (wsh/lookup-page-objects state) + (let [objects (dsh/lookup-page-objects state) selected (dm/get-in state [:workspace-local :selected])] {:objects objects :selected selected})) st/state (fn [v1 v2] @@ -131,7 +140,7 @@ (def selected-shapes (l/derived (fn [{:keys [objects selected]}] - (wsh/process-selected-shapes objects selected)) + (dsh/process-selected-shapes objects selected)) selected-shapes-data)) (defn make-selected-ref @@ -217,20 +226,10 @@ (def rulers? (l/derived #(contains? % :rulers) workspace-layout)) -(def workspace-file - "A ref to a striped vision of file (without data)." - (l/derived (fn [state] - (let [file (:workspace-file state) - data (:workspace-data state)] - (-> file - (dissoc :data) - ;; FIXME: still used in sitemaps but sitemaps - ;; should declare its own lense for it - (assoc :pages (:pages data))))) - st/state =)) - +;; FIXME: rename to current-file-data (def workspace-data - (l/derived :workspace-data st/state)) + "Currently working file data on workspace" + (l/derived dsh/lookup-file-data st/state)) (def workspace-file-colors (l/derived (fn [{:keys [id] :as data}] @@ -238,18 +237,19 @@ workspace-data =)) -(def workspace-recent-colors +(def recent-colors + "Recent colors for the currently selected file" (l/derived (fn [state] (when-let [file-id (:current-file-id state)] (dm/get-in state [:recent-colors file-id]))) st/state)) -;; FIXME: fonts are not prefixed, so the recent font list is shared -;; across all teams. This may not be expected behavior -(def workspace-recent-fonts - (l/derived (fn [data] - (get data :recent-fonts [])) - workspace-data)) +(def recent-fonts + "Recent fonts for the currently selected file" + (l/derived (fn [state] + (when-let [file-id (:current-file-id state)] + (dm/get-in state [:recent-fonts file-id]))) + st/state)) (def workspace-file-typography (l/derived :typographies workspace-data)) @@ -258,23 +258,20 @@ (l/derived :workspace-presence st/state)) (def workspace-page - (l/derived (fn [state] - (let [page-id (:current-page-id state) - data (:workspace-data state)] - (dm/get-in data [:pages-index page-id]))) - st/state)) + "Ref to currently active page on workspace" + (l/derived dsh/lookup-page st/state)) (def workspace-page-flows (l/derived #(-> % :flows not-empty) workspace-page)) (defn workspace-page-object-by-id [page-id shape-id] - (l/derived #(wsh/lookup-shape % page-id shape-id) st/state =)) + (l/derived #(dsh/lookup-shape % page-id shape-id) st/state =)) ;; TODO: Looks like using the `=` comparator can be pretty expensive ;; on large pages, we are using this for some reason? (def workspace-page-objects - (l/derived wsh/lookup-page-objects st/state =)) + (l/derived dsh/lookup-page-objects st/state =)) (def workspace-read-only? (l/derived :read-only? workspace-global)) @@ -348,7 +345,7 @@ (l/derived (fn [state] {:modifiers (:workspace-modifiers state) - :objects (wsh/lookup-page-objects state)}) + :objects (dsh/lookup-page-objects state)}) st/state (fn [a b] (and (= (:modifiers a) (:modifiers b)) @@ -379,11 +376,11 @@ (l/derived #(get % frame-id) workspace-frame-modifiers =)) (defn select-bool-children [id] - (l/derived (partial wsh/select-bool-children id) st/state =)) + (l/derived #(dsh/select-bool-children % id) st/state =)) (def selected-data - (l/derived #(let [selected (wsh/lookup-selected %) - objects (wsh/lookup-page-objects %)] + (l/derived #(let [selected (dsh/lookup-selected %) + objects (dsh/lookup-page-objects %)] (hash-map :selected selected :objects objects)) st/state =)) @@ -415,7 +412,7 @@ [ids] (l/derived (fn [state] - (let [objects (wsh/lookup-page-objects state)] + (let [objects (dsh/lookup-page-objects state)] (into [] (comp (map (d/getf objects)) (filter (partial ctl/flex-layout-immediate-child? objects))) diff --git a/frontend/src/app/main/router.cljs b/frontend/src/app/main/router.cljs index 39e06b812..58e421983 100644 --- a/frontend/src/app/main/router.cljs +++ b/frontend/src/app/main/router.cljs @@ -28,7 +28,8 @@ (r/map->Match data)) (defn resolve - ([router id] (resolve router id {})) + ([router id] + (resolve router id {})) ([router id params] (when router (when-let [match (r/match-by-name router id)] diff --git a/frontend/src/app/main/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs index c14c55048..c1797338d 100644 --- a/frontend/src/app/main/ui/comments.cljs +++ b/frontend/src/app/main/ui/comments.cljs @@ -37,14 +37,13 @@ [okulary.core :as l] [rumext.v2 :as mf])) -(def comments-local-options (l/derived :options refs/comments-local)) +(def ^:private ref:comments-local-options + (l/derived :options refs/comments-local)) (def mentions-context (mf/create-context nil)) - (def r-mentions-split #"@\[[^\]]*\]\([^\)]*\)") (def r-mentions #"@\[([^\]]*)\]\(([^\)]*)\)") - (defn- parse-comment "Parse a comment into its elements (texts and mentions)" [comment] @@ -58,7 +57,7 @@ :content user :data {:id id}}))))) -(defn parse-nodes +(defn- parse-nodes "Parse the nodes to format a comment" [node] (->> (dom/get-children node) @@ -72,8 +71,7 @@ (.-textContent node)))) (str/join ""))) - -(defn create-text-node +(defn- create-text-node "Creates a text-only node" ([] (create-text-node "")) @@ -82,7 +80,7 @@ (dom/set-data! "type" "text") (dom/set-html! (if (empty? text) "​" text))))) -(defn create-mention-node +(defn- create-mention-node "Creates a mention node" [id fullname] (-> (dom/create-element "span") @@ -91,7 +89,7 @@ (dom/set-data! "fullname" fullname) (obj/set! "textContent" fullname))) -(defn current-text-node +(defn- current-text-node "Retrieves the text node and the offset that the cursor is positioned on" [node] @@ -108,7 +106,7 @@ (when (= node container) [span-node anchor-offset]))))) -(defn absolute-offset +(defn- absolute-offset [node child offset] (loop [nodes (seq (dom/get-children node)) acc 0] @@ -118,7 +116,7 @@ (recur (rest nodes) (+ acc (.-length (.-textContent head))))) nil))) -(defn get-prev-node +(defn- get-prev-node [parent node] (->> (d/with-prev (dom/get-children parent)) (d/seek (fn [[it _]] (= node it))) @@ -126,8 +124,7 @@ ;; Component that renders the component content (mf/defc comment-content* - {::mf/props :obj - ::mf/private true} + {::mf/private true} [{:keys [content]}] (let [comment-elements (mf/use-memo (mf/deps content) #(parse-comment content))] (for [[idx {:keys [type content]}] (d/enumerate comment-elements)] @@ -141,22 +138,20 @@ ;; Input text for comments with mentions (mf/defc comment-input* - {::mf/props :obj - ::mf/private true - ::mf/wrap-props false} - [{:keys [value placeholder max-length autofocus? on-focus on-blur on-change on-esc on-ctrl-enter]}] + {::mf/private true} + [{:keys [value placeholder max-length autofocus on-focus on-blur on-change on-esc on-ctrl-enter]}] - (let [value (d/nilv value "") - prev-value (h/use-previous value) + (let [value (d/nilv value "") + prev-value (h/use-previous value) - local-ref (mf/use-ref nil) - mentions-str (mf/use-ctx mentions-context) - cur-mention (mf/use-var nil) + local-ref (mf/use-ref nil) + mentions-s (mf/use-ctx mentions-context) + cur-mention (mf/use-var nil) - prev-selection (mf/use-var nil) + prev-selection (mf/use-var nil) init-input - (mf/use-callback + (mf/use-fn (fn [node] (mf/set-ref-val! local-ref node) (when node @@ -167,13 +162,13 @@ nil))))) handle-input - (mf/use-callback + (mf/use-fn (mf/deps on-change) (fn [] (let [node (mf/ref-val local-ref) children (dom/get-children node)] - (doseq [child-node children] + (doseq [^js child-node children] ;; Remove nodes that are not span. This can happen if the user copy/pastes (when (not= (.-tagName child-node) "SPAN") (.remove child-node)) @@ -198,7 +193,7 @@ (on-change new-input)))))) handle-select - (mf/use-callback + (mf/use-fn (fn [] (let [node (mf/ref-val local-ref) selection (wapi/get-selection) @@ -240,16 +235,16 @@ (if (re-matches #"@\w*" mention-text) (do (reset! cur-mention mention-text) - (rx/push! mentions-str {:type :display-mentions}) + (rx/push! mentions-s {:type :display-mentions}) (let [mention (subs mention-text 1)] (when (d/not-empty? mention) - (rx/push! mentions-str {:type :filter-mentions :data mention})))) + (rx/push! mentions-s {:type :filter-mentions :data mention})))) (do (reset! cur-mention nil) - (rx/push! mentions-str {:type :hide-mentions})))))))) + (rx/push! mentions-s {:type :hide-mentions})))))))) handle-focus - (mf/use-callback + (mf/use-fn (fn [event] (dom/prevent-default event) (dom/set-css-property! (mf/ref-val local-ref) "--placeholder" "") @@ -257,7 +252,7 @@ (on-focus event)))) handle-blur - (mf/use-callback + (mf/use-fn (mf/deps value) (fn [event] (when (empty? value) @@ -268,38 +263,40 @@ (on-blur event)))) handle-insert-mention - (fn [data] - (let [node (mf/ref-val local-ref) - [span-node offset] (current-text-node node)] - (when span-node - (let [node-text - (dom/get-text span-node) + (mf/use-fn + (mf/deps on-change) + (fn [data] + (let [node (mf/ref-val local-ref) + [span-node offset] (current-text-node node)] + (when span-node + (let [node-text + (dom/get-text span-node) - current-at-symbol - (or (str/last-index-of (subs node-text 0 offset) "@") - (absolute-offset node span-node offset)) + current-at-symbol + (or (str/last-index-of (subs node-text 0 offset) "@") + (absolute-offset node span-node offset)) - mention - (re-find #"@\w*" (subs node-text current-at-symbol)) + mention + (re-find #"@\w*" (subs node-text current-at-symbol)) - prefix - (subs node-text 0 current-at-symbol) + prefix + (subs node-text 0 current-at-symbol) - suffix - (subs node-text (+ current-at-symbol (count mention))) + suffix + (subs node-text (+ current-at-symbol (count mention))) - mention-span (create-mention-node (-> data :user :id) (-> data :user :fullname)) - after-span (create-text-node (dm/str " " suffix)) - sel (wapi/get-selection)] + mention-span (create-mention-node (-> data :user :id) (-> data :user :fullname)) + after-span (create-text-node (dm/str " " suffix)) + sel (wapi/get-selection)] - (dom/set-html! span-node (if (empty? prefix) "​" prefix)) - (dom/insert-after! node span-node mention-span) - (dom/insert-after! node mention-span after-span) - (wapi/set-cursor-after! after-span) - (wapi/collapse-end! sel) + (dom/set-html! span-node (if (empty? prefix) "​" prefix)) + (dom/insert-after! node span-node mention-span) + (dom/insert-after! node mention-span after-span) + (wapi/set-cursor-after! after-span) + (wapi/collapse-end! sel) - (when on-change - (on-change (parse-nodes node))))))) + (when (fn? on-change) + (on-change (parse-nodes node)))))))) handle-key-down (mf/use-fn @@ -314,22 +311,22 @@ (and @cur-mention (kbd/enter? event)) (do (dom/prevent-default event) (dom/stop-propagation event) - (rx/push! mentions-str {:type :insert-selected-mention})) + (rx/push! mentions-s {:type :insert-selected-mention})) (and @cur-mention (kbd/down-arrow? event)) (do (dom/prevent-default event) (dom/stop-propagation event) - (rx/push! mentions-str {:type :insert-next-mention})) + (rx/push! mentions-s {:type :insert-next-mention})) (and @cur-mention (kbd/up-arrow? event)) (do (dom/prevent-default event) (dom/stop-propagation event) - (rx/push! mentions-str {:type :insert-prev-mention})) + (rx/push! mentions-s {:type :insert-prev-mention})) (and @cur-mention (kbd/esc? event)) (do (dom/prevent-default event) (dom/stop-propagation event) - (rx/push! mentions-str {:type :hide-mentions})) + (rx/push! mentions-s {:type :hide-mentions})) (and (kbd/esc? event) (fn? on-esc)) (on-esc event) @@ -362,56 +359,49 @@ (.remove prev-node)))))))] (mf/use-layout-effect - (mf/deps autofocus?) + (mf/deps autofocus) (fn [] - (when autofocus? + (when autofocus (dom/focus! (mf/ref-val local-ref))))) ;; Creates the handlers for selection - (mf/use-effect - (mf/deps handle-select) - (fn [] - (let [handle-select* handle-select] - (js/document.addEventListener "selectionchange" handle-select*) - #(js/document.removeEventListener "selectionchange" handle-select*)))) + (mf/with-effect [handle-select] + (let [handle-select* handle-select] + (js/document.addEventListener "selectionchange" handle-select*) + #(js/document.removeEventListener "selectionchange" handle-select*))) ;; Effect to communicate with the mentions panel - (mf/use-effect - (fn [] - (when mentions-str - (->> mentions-str - (rx/subs! - (fn [{:keys [type data]}] - (case type - :insert-mention - (handle-insert-mention data) + (mf/with-effect [] + (when mentions-s + (->> mentions-s + (rx/subs! + (fn [{:keys [type data]}] + (case type + :insert-mention + (handle-insert-mention data) - nil))))))) + nil)))))) ;; Auto resize input to display the comment - (mf/use-layout-effect - nil - (fn [] - (let [node (mf/ref-val local-ref)] - (set! (.-height (.-style node)) "0") - (set! (.-height (.-style node)) (str (+ 2 (.-scrollHeight node)) "px"))))) + (mf/with-layout-effect nil + (let [^js node (mf/ref-val local-ref)] + (set! (.-height (.-style node)) "0") + (set! (.-height (.-style node)) (str (+ 2 (.-scrollHeight node)) "px")))) - (mf/use-effect - (mf/deps value prev-value) - (fn [] - (let [node (mf/ref-val local-ref)] - (cond - (and (d/not-empty? prev-value) (empty? value)) - (do (dom/set-html! node "") - (dom/append-child! node (create-text-node)) - (dom/set-css-property! node "--placeholder" "") - (dom/focus! node)) + (mf/with-effect [value prev-value] + (let [node (mf/ref-val local-ref)] + (cond + (and (d/not-empty? prev-value) (empty? value)) + (do (dom/set-html! node "") + (dom/append-child! node (create-text-node)) + (dom/set-css-property! node "--placeholder" "") + (dom/focus! node)) - (and (some? node) (empty? value) (not (dom/focus? node))) - (dom/set-css-property! node "--placeholder" (dm/str "\"" placeholder "\"")) + (and (some? node) (empty? value) (not (dom/focus? node))) + (dom/set-css-property! node "--placeholder" (dm/str "\"" placeholder "\"")) - (some? node) - (dom/set-css-property! node "--placeholder" ""))))) + (some? node) + (dom/set-css-property! node "--placeholder" "")))) [:div {:role "textbox" @@ -425,84 +415,82 @@ :on-blur handle-blur}])) (mf/defc mentions-panel* - {::mf/props :obj - ::mf/private true} - [{:keys [profiles]}] + [] + (let [mentions-s (mf/use-ctx mentions-context) + profile (mf/deref refs/profile) + profiles (mf/deref refs/profiles) - (let [mentions-str (mf/use-ctx mentions-context) + state* + (mf/use-state + #(do {:display false + :mention-filter "" + :selected 0})) - profile (mf/deref refs/profile) - - mention-state - (mf/use-state {:display? false - :mention-filter "" - :selected 0}) - - {:keys [display? mention-filter selected]} @mention-state + {:keys [display mention-filter selected]} + (deref state*) mentions-users - (mf/use-memo - (mf/deps mention-filter) - #(->> (vals profiles) - (filter - (fn [{:keys [id fullname email]}] - (and - (not= id (:id profile)) - (or (not mention-filter) - (empty? mention-filter) - (str/includes? (str/lower fullname) (str/lower mention-filter)) - (str/includes? (str/lower email) (str/lower mention-filter)))))) + (mf/with-memo [mention-filter] + + + (->> (vals profiles) + (filter (fn [{:keys [id fullname email]}] + (and + (not= id (:id profile)) + (or (not mention-filter) + (empty? mention-filter) + (str/includes? (str/lower fullname) (str/lower mention-filter)) + (str/includes? (str/lower email) (str/lower mention-filter)))))) (take 4) (into []))) - selected (mth/clamp selected 0 (dec (count mentions-users))) + selected + (mth/clamp selected 0 (dec (count mentions-users))) handle-click-mention - (mf/use-callback + (mf/use-fn (fn [event] (dom/prevent-default event) (dom/stop-propagation event) (let [id (-> (dom/get-current-target event) (dom/get-data "user-id") (uuid/uuid))] - (rx/push! mentions-str {:type :insert-mention - :data {:user (get profiles id)}}))))] + (rx/push! mentions-s {:type :insert-mention + :data {:user (get profiles id)}}))))] - (mf/use-effect - (mf/deps mentions-users selected) - (fn [] - (let [sub - (->> mentions-str - (rx/subs! - (fn [{:keys [type data]}] - (case type - ;; Display the mentions dialog - :display-mentions - (swap! mention-state assoc :display? true) + (mf/with-effect [mentions-users selected] + (let [sub + (->> mentions-s + (rx/subs! + (fn [{:keys [type data]}] + (case type + ;; Display the mentions dialog + :display-mentions + (swap! state* assoc :display true) - ;; Hide mentions - :hide-mentions - (swap! mention-state assoc :display? false :mention-filter "") + ;; Hide mentions + :hide-mentions + (swap! state* assoc :display false :mention-filter "") - ;; Filter the metions by some characters - :filter-mentions - (swap! mention-state assoc :mention-filter data) + ;; Filter the metions by some characters + :filter-mentions + (swap! state* assoc :mention-filter data) - :insert-selected-mention - (rx/push! mentions-str {:type :insert-mention - :data {:user (get mentions-users selected)}}) + :insert-selected-mention + (rx/push! mentions-s {:type :insert-mention + :data {:user (get mentions-users selected)}}) - :insert-next-mention - (swap! mention-state update :selected #(mth/clamp (inc %) 0 (dec (count mentions-users)))) + :insert-next-mention + (swap! state* update :selected #(mth/clamp (inc %) 0 (dec (count mentions-users)))) - :insert-prev-mention - (swap! mention-state update :selected #(mth/clamp (dec %) 0 (dec (count mentions-users)))) + :insert-prev-mention + (swap! state* update :selected #(mth/clamp (dec %) 0 (dec (count mentions-users)))) - ;; - nil))))] - #(rx/dispose! sub)))) + ;; + nil))))] + #(rx/dispose! sub))) - (when display? + (when ^boolean display [:div {:class (stl/css :comments-mentions-choice)} (if (empty? mentions-users) [:div {:class (stl/css :comments-mentions-empty)} @@ -523,15 +511,15 @@ {::mf/props :obj ::mf/private true} [] - (let [mentions-str (mf/use-ctx mentions-context) + (let [mentions-s (mf/use-ctx mentions-context) display-mentions* (mf/use-state false) handle-mouse-down - (mf/use-callback + (mf/use-fn (fn [event] (dom/prevent-default event) (dom/stop-propagation event) - (rx/push! mentions-str {:type :display-mentions})))] + (rx/push! mentions-s {:type :display-mentions})))] (mf/use-effect (fn [] @@ -542,7 +530,7 @@ :display-mentions (reset! display-mentions* true) :hide-mentions (reset! display-mentions* false) nil)) - mentions-str)] + mentions-s)] #(rx/dispose! sub)))) [:> icon-button* @@ -561,8 +549,7 @@ [:maybe [:enum "read" "unread" "solved"]]]]) (mf/defc comment-avatar* - {::mf/props :obj - ::mf/schema schema:comment-avatar} + {::mf/schema schema:comment-avatar} [{:keys [image variant class] :rest props}] (let [variant (or variant "read") class (dm/str class " " (stl/css-case :avatar true @@ -577,8 +564,7 @@ :avatar-darken (= variant "solved"))}]])) (mf/defc comment-info* - {::mf/props :obj - ::mf/private true} + {::mf/private true} [{:keys [item profile]}] [:* [:div {:class (stl/css :author)} @@ -642,11 +628,12 @@ (fn [] (st/emit! (dcm/add-comment thread @content)) (on-cancel)))] + [:div {:class (stl/css :form)} [:> comment-input* {:value @content :placeholder (tr "labels.reply.thread") - :autofocus? true + :autofocus true :on-blur on-blur :on-focus on-focus :on-ctrl-enter on-submit @@ -664,8 +651,7 @@ (tr "labels.post")]])])) (mf/defc comment-edit-form* - {::mf/props :obj - ::mf/private true} + {::mf/private true} [{:keys [content on-submit on-cancel]}] (let [content (mf/use-state content) @@ -684,7 +670,7 @@ [:div {:class (stl/css :form)} [:> comment-input* {:value @content - :autofocus? true + :autofocus true :on-ctrl-enter on-submit* :on-change on-change :max-length 750}] @@ -699,11 +685,10 @@ (tr "labels.post")]]])) (mf/defc comment-floating-thread-draft* - {::mf/props :obj} - [{:keys [draft zoom on-cancel on-submit position-modifier profiles]}] + [{:keys [draft zoom on-cancel on-submit position-modifier]}] (let [profile (mf/deref refs/profile) - mentions-str (mf/use-memo #(rx/subject)) + mentions-s (mf/use-memo #(rx/subject)) position (cond-> (:position draft) (some? position-modifier) @@ -736,7 +721,7 @@ (mf/deps draft) (partial on-submit draft))] - [:> (mf/provider mentions-context) {:value mentions-str} + [:> (mf/provider mentions-context) {:value mentions-s} [:div {:class (stl/css :floating-preview-wrapper) :data-testid "floating-thread-bubble" @@ -753,7 +738,7 @@ [:> comment-input* {:placeholder (tr "labels.write-new-comment") :value (or content "") - :autofocus? true + :autofocus true :on-esc on-esc :on-change on-change :on-ctrl-enter on-submit @@ -769,15 +754,14 @@ :disabled disabled?} (tr "labels.post")]]] - [:> mentions-panel* {:profiles profiles}]]])) + [:> mentions-panel*]]])) (mf/defc comment-floating-thread-header* - {::mf/props :obj - ::mf/private true} - [{:keys [profiles thread origin]}] - (let [owner (get profiles (:owner-id thread)) + {::mf/private true} + [{:keys [thread origin]}] + (let [owner (dcm/get-owner thread) profile (mf/deref refs/profile) - options (mf/deref comments-local-options) + options (mf/deref ref:comments-local-options) toggle-resolved (mf/use-fn @@ -842,12 +826,11 @@ (tr "labels.delete-comment-thread")]]]])) (mf/defc comment-floating-thread-item* - {::mf/props :obj - ::mf/private true} - [{:keys [comment thread profiles]}] - (let [owner (get profiles (:owner-id comment)) + {::mf/private true} + [{:keys [comment thread]}] + (let [owner (dcm/get-owner comment) profile (mf/deref refs/profile) - options (mf/deref comments-local-options) + options (mf/deref ref:comments-local-options) edition? (mf/use-state false) on-toggle-options @@ -925,8 +908,8 @@ (defn- offset-position [position viewport zoom bubble-margin] (let [viewport (or viewport {:offset-x 0 :offset-y 0 :width 0 :height 0}) - base-x (+ (* (:x position) zoom) (:offset-x viewport)) - base-y (+ (* (:y position) zoom) (:offset-y viewport)) + base-x (+ (* (:x position) zoom) (:offset-x viewport)) + base-y (+ (* (:y position) zoom) (:offset-y viewport)) x (:x position) y (:y position) @@ -945,11 +928,10 @@ {:x x :y y :h-dir h-dir :v-dir v-dir})) (mf/defc comment-floating-thread* - {::mf/props :obj - ::mf/wrap [mf/memo]} - [{:keys [thread zoom profiles origin position-modifier viewport]}] + {::mf/wrap [mf/memo]} + [{:keys [thread zoom origin position-modifier viewport]}] (let [ref (mf/use-ref) - mentions-str (mf/use-memo #(rx/subject)) + mentions-s (mf/use-memo #(rx/subject)) thread-id (:id thread) thread-pos (:position thread) @@ -960,7 +942,7 @@ max-height (when (some? viewport) (int (* (:height viewport) 0.5))) ;; We should probably look for a better way of doing this. - bubble-margin {:x 24 :y 24} + bubble-margin (gpt/point 24 24) pos (offset-position base-pos viewport zoom bubble-margin) margin-x (* (:x bubble-margin) (if (= (:h-dir pos) :left) -1 1)) @@ -988,7 +970,7 @@ (when-let [node (mf/ref-val ref)] (dom/scroll-into-view-if-needed! node))) - [:& (mf/provider mentions-context) {:value mentions-str} + [:> (mf/provider mentions-context) {:value mentions-s} (when (some? first-comment) [:div {:class (stl/css-case :floating-thread-wrapper true :left (= (:h-dir pos) :left) @@ -1000,29 +982,25 @@ :on-click dom/stop-propagation} [:div {:class (stl/css :floating-thread-header)} - [:> comment-floating-thread-header* {:profiles profiles - :thread thread + [:> comment-floating-thread-header* {:thread thread :origin origin}]] [:div {:class (stl/css :floating-thread-main)} [:> comment-floating-thread-item* {:comment first-comment - :profiles profiles :thread thread}] (for [item (rest comments)] [:* {:key (dm/str (:id item))} - [:> comment-floating-thread-item* {:comment item - :profiles profiles}]])] + [:> comment-floating-thread-item* {:comment item}]])] [:> comment-reply-form* {:thread thread}] - [:> mentions-panel* {:profiles profiles}]])])) + [:> mentions-panel*]])])) (mf/defc comment-floating-bubble* - {::mf/props :obj - ::mf/wrap [mf/memo]} - [{:keys [thread profiles zoom is-open on-click origin position-modifier]}] - (let [owner (get profiles (:owner-id thread)) - + {::mf/wrap [mf/memo]} + [{:keys [thread zoom is-open on-click origin position-modifier]}] + (let [owner (mf/with-memo [thread] + (dcm/get-owner thread)) base-pos (cond-> (:position thread) (some? position-modifier) (gpt/transform position-modifier)) @@ -1036,11 +1014,12 @@ position (:position thread) frame-id (:frame-id thread) - state (mf/use-state {:hover? false - :grabbing? false - :new-position-x nil - :new-position-y nil - :new-frame-id frame-id}) + state (mf/use-state + #(do {:is-hover false + :is-grabbing false + :new-position-x nil + :new-position-y nil + :new-frame-id frame-id})) pos-x (floor (* (or (:new-position-x @state) (:x base-pos)) zoom)) pos-y (floor (* (or (:new-position-y @state) (:y base-pos)) zoom)) @@ -1050,7 +1029,7 @@ (mf/deps origin was-open? is-open drag?) (fn [event] (when (not= origin :viewer) - (swap! state assoc :grabbing? true) + (swap! state assoc :is-grabbing true) (mf/set-ref-val! was-open? is-open) (when is-open (st/emit! (dcm/close-thread))) (mf/set-ref-val! drag? false) @@ -1064,7 +1043,7 @@ (mf/deps origin thread (select-keys @state [:new-position-x :new-position-y :new-frame-id])) (fn [event] (when (not= origin :viewer) - (swap! state assoc :grabbing? false) + (swap! state assoc :is-grabbing false) (dom/stop-propagation event) (dom/release-pointer event) (mf/set-ref-val! dragging-ref false) @@ -1100,28 +1079,28 @@ (fn [event] (dom/stop-propagation event) (when (false? is-open) - (swap! state assoc :hover? true)))) + (swap! state assoc :is-hover true)))) on-pointer-leave (mf/use-fn (fn [event] (dom/stop-propagation event) - (swap! state assoc :hover? false))) + (swap! state assoc :is-hover false))) on-click* (mf/use-fn - (mf/deps origin thread on-click was-open? drag? (select-keys @state [:hover?])) + (mf/deps origin thread on-click was-open? drag? (select-keys @state [:is-hover])) (fn [event] (dom/stop-propagation event) (when (or (and (mf/ref-val was-open?) (mf/ref-val drag?)) (and (not (mf/ref-val was-open?)) (not (mf/ref-val drag?)))) - (swap! state assoc :hover? false) + (swap! state assoc :is-hover false) (st/emit! (dcm/open-thread thread))) (when (= origin :viewer) (on-click thread))))] - [:div {:style {:top (str pos-y "px") - :left (str pos-x "px")} + [:div {:style {:top (dm/str pos-y "px") + :left (dm/str pos-x "px")} :on-pointer-down on-pointer-down :on-pointer-up on-pointer-up :on-pointer-move on-pointer-move @@ -1129,29 +1108,30 @@ :on-pointer-leave on-pointer-leave :on-click on-click* :class (stl/css-case :floating-preview-wrapper true - :floating-preview-bubble (false? (:hover? @state)) - :grabbing (true? (:grabbing? @state)))} + :floating-preview-bubble (false? (:is-hover @state)) + :grabbing (true? (:is-grabbing @state)))} - (if (:hover? @state) + (if (:is-hover @state) [:div {:class (stl/css :floating-thread-wrapper :floating-preview-displacement)} [:div {:class (stl/css :floating-thread-item-wrapper)} [:div {:class (stl/css :floating-thread-item)} [:> comment-info* {:item thread :profile owner}]]]] - [:> comment-avatar* {:image (cfg/resolve-profile-photo-url owner) - :class (stl/css :avatar-lg) - :data-testid (str "floating-thread-bubble-" (:seqn thread)) - :variant (cond (:is-resolved thread) "solved" - (pos? (:count-unread-comments thread)) "unread" - :else "read")}])])) + [:> comment-avatar* + {:image (cfg/resolve-profile-photo-url owner) + :class (stl/css :avatar-lg) + :data-testid (dm/str "floating-thread-bubble-" (:seqn thread)) + :variant (cond + (:is-resolved thread) "solved" + (pos? (:count-unread-comments thread)) "unread" + :else "read")}])])) (mf/defc comment-sidebar-thread-item* - {::mf/props :obj - ::mf/private true} - [{:keys [item profiles on-click]}] - (let [owner (get profiles (:owner-id item)) - + {::mf/private true} + [{:keys [item on-click]}] + (let [owner (dcm/get-owner item) + ;; FIXME frame (mf/deref (refs/workspace-page-object-by-id (:page-id item) (:frame-id item))) on-click* @@ -1176,21 +1156,18 @@ :profile owner}]])) (mf/defc comment-sidebar-thread-group* - {::mf/props :obj} - [{:keys [group profiles on-thread-click]}] + [{:keys [group on-thread-click]}] [:div (for [item (:items group)] [:> comment-sidebar-thread-item* {:item item :on-click on-thread-click - :profiles profiles :key (:id item)}])]) (mf/defc comment-dashboard-thread-item* - {::mf/props :obj - ::mf/private true} - [{:keys [item profiles on-click]}] - (let [owner (get profiles (:owner-id item)) + {::mf/private true} + [{:keys [item on-click]}] + (let [owner (dcm/get-owner item) on-click* (mf/use-fn @@ -1215,12 +1192,10 @@ :profile owner}]])) (mf/defc comment-dashboard-thread-group* - {::mf/props :obj} - [{:keys [group profiles on-thread-click]}] + [{:keys [group on-thread-click]}] [:div (for [item (:items group)] [:> comment-dashboard-thread-item* {:item item :on-click on-thread-click - :profiles profiles :key (:id item)}])]) diff --git a/frontend/src/app/main/ui/dashboard/comments.cljs b/frontend/src/app/main/ui/dashboard/comments.cljs index b0700e735..17356a5de 100644 --- a/frontend/src/app/main/ui/dashboard/comments.cljs +++ b/frontend/src/app/main/ui/dashboard/comments.cljs @@ -50,9 +50,9 @@ (mf/defc comments-section [{:keys [profile team show? on-hide-comments]}] (let [threads-map (mf/deref refs/comment-threads) - profiles (mf/deref refs/profiles) - team-id (:id team) + ;; FIXME: with-memo + team-id (:id team) tgroups (->> (vals threads-map) (sort-by :modified-at) (reverse) @@ -93,14 +93,12 @@ [:> cmt/comment-dashboard-thread-group* {:group (first tgroups) :on-thread-click on-navigate - :show-file-name true - :profiles profiles}] + :show-file-name true}] (for [tgroup (rest tgroups)] [:> cmt/comment-dashboard-thread-group* {:group tgroup :on-thread-click on-navigate :show-file-name true - :profiles profiles :key (:page-id tgroup)}])] [:div {:class (stl/css :thread-groups-placeholder)} diff --git a/frontend/src/app/main/ui/flex_controls/gap.cljs b/frontend/src/app/main/ui/flex_controls/gap.cljs index e04024d86..963f9442d 100644 --- a/frontend/src/app/main/ui/flex_controls/gap.cljs +++ b/frontend/src/app/main/ui/flex_controls/gap.cljs @@ -14,8 +14,8 @@ [app.common.geom.shapes.points :as gpo] [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl] + [app.main.data.helpers :as dsh] [app.main.data.workspace.modifiers :as dwm] - [app.main.data.workspace.state-helpers :as wsh] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.css-cursors :as cur] @@ -135,7 +135,7 @@ negate {:column-gap (if flip-x true false) :row-gap (if flip-y true false)} - objects (wsh/lookup-page-objects @st/state) + objects (dsh/lookup-page-objects @st/state) children (->> (cfh/get-immediate-children objects frame-id) (remove ctl/position-absolute?)) diff --git a/frontend/src/app/main/ui/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs index db9d66c05..028a55eed 100644 --- a/frontend/src/app/main/ui/viewer/comments.cljs +++ b/frontend/src/app/main/ui/viewer/comments.cljs @@ -127,7 +127,7 @@ (mf/defc comments-layer {::mf/props :obj} - [{:keys [zoom file users frame page]}] + [{:keys [zoom file frame page]}] (let [profile (mf/deref refs/profile) local (mf/deref refs/comments-local) @@ -208,7 +208,6 @@ (for [item threads] [:> cmt/comment-floating-bubble* {:thread item - :profiles users :position-modifier modifier1 :zoom zoom :on-click on-bubble-click @@ -219,7 +218,6 @@ (when-let [thread (get threads-map open-thread-id)] [:> cmt/comment-floating-thread* {:thread thread - :profiles users :position-modifier modifier1 :viewport {:offset-x 0 :offset-y 0 :width (:width vsize) :height (:height vsize)} :zoom zoom}]) @@ -227,7 +225,6 @@ (when-let [draft (:draft local)] [:> cmt/comment-floating-thread-draft* {:draft draft - :profiles users :position-modifier modifier1 :on-cancel on-draft-cancel :on-submit on-draft-submit diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs index 325834266..c05a86229 100644 --- a/frontend/src/app/main/ui/workspace.cljs +++ b/frontend/src/app/main/ui/workspace.cljs @@ -9,11 +9,13 @@ (:require [app.common.data.macros :as dm] [app.main.data.common :as dcm] + [app.main.data.helpers :as dsh] [app.main.data.persistence :as dps] [app.main.data.plugins :as dpl] [app.main.data.workspace :as dw] [app.main.features :as features] [app.main.refs :as refs] + [app.main.router :as-alias rt] [app.main.store :as st] [app.main.ui.context :as ctx] [app.main.ui.ds.product.loader :refer [loader*]] @@ -21,7 +23,7 @@ [app.main.ui.hooks.resize :refer [use-resize-observer]] [app.main.ui.modal :refer [modal-container*]] [app.main.ui.workspace.colorpicker] - [app.main.ui.workspace.context-menu :refer [context-menu]] + [app.main.ui.workspace.context-menu :refer [context-menu*]] [app.main.ui.workspace.coordinates :as coordinates] [app.main.ui.workspace.libraries] [app.main.ui.workspace.nudge] @@ -32,7 +34,7 @@ [app.main.ui.workspace.sidebar.history :refer [history-toolbox*]] [app.main.ui.workspace.tokens.modals] [app.main.ui.workspace.tokens.modals.themes] - [app.main.ui.workspace.viewport :refer [viewport]] + [app.main.ui.workspace.viewport :refer [viewport*]] [app.util.debug :as dbg] [app.util.dom :as dom] [app.util.globals :as globals] @@ -41,27 +43,19 @@ [okulary.core :as l] [rumext.v2 :as mf])) -(defn- make-file-ready-ref +(defn- make-workspace-ready-ref [file-id] (l/derived (fn [state] - (let [data (:workspace-data state)] - (and (:workspace-ready state) - (= file-id (:current-file-id state)) - (= file-id (:id data))))) + (and (= file-id (:workspace-ready state)) + (some? (dsh/lookup-file-data state file-id)))) st/state)) -(defn- make-page-ready-ref - [page-id] - (l/derived (fn [state] - (and (some? page-id) - (= page-id (:current-page-id state)))) - st/state)) - -(mf/defc workspace-content - {::mf/wrap-props false} - [{:keys [file layout page-id wglobal]}] +(mf/defc workspace-content* + {::mf/private true} + [{:keys [file layout page wglobal]}] (let [palete-size (mf/use-state nil) - selected (mf/deref refs/selected-shapes) + selected (mf/deref refs/selected-shapes) + page-id (:id page) {:keys [vport] :as wlocal} (mf/deref refs/workspace-local) {:keys [options-mode]} wglobal @@ -102,14 +96,16 @@ [:button {:on-click #(st/emit! dw/reinitialize-undo)} "CLEAR"] [:> history-toolbox*]]) - [:& viewport {:file file - :wlocal wlocal - :wglobal wglobal - :selected selected - :layout layout - :palete-size - (when (and (or colorpalette? textpalette?) (not hide-ui?)) - @palete-size)}]]] + [:> viewport* + {:file file + :page page + :wlocal wlocal + :wglobal wglobal + :selected selected + :layout layout + :palete-size + (when (and (or colorpalette? textpalette?) (not hide-ui?)) + @palete-size)}]]] (when-not hide-ui? [:* @@ -125,21 +121,17 @@ :page-id page-id}]])])) (mf/defc workspace-loader* - {::mf/props :obj - ::mf/private true} + {::mf/private true} [] [:> loader* {:title (tr "labels.loading") :class (stl/css :workspace-loader) :overlay true}]) (mf/defc workspace-page* - {::mf/props :obj - ::mf/private true} + {::mf/private true} [{:keys [page-id file layout wglobal]}] - (let [page-id (hooks/use-equal-memo page-id) - page-ready* (mf/with-memo [page-id] - (make-page-ready-ref page-id)) - page-ready? (mf/deref page-ready*)] + (let [page-id (hooks/use-equal-memo page-id) + page (mf/deref refs/workspace-page)] (mf/with-effect [] (let [focus-out #(st/emit! (dw/workspace-focus-lost)) @@ -149,29 +141,39 @@ (mf/with-effect [page-id] (if (some? page-id) (st/emit! (dw/initialize-page page-id)) - (st/emit! (dcm/go-to-workspace))) + (st/emit! (dcm/go-to-workspace ::rt/replace true))) + (fn [] (when (some? page-id) (st/emit! (dw/finalize-page page-id))))) - (if ^boolean page-ready? - [:& workspace-content {:page-id page-id - :file file - :wglobal wglobal - :layout layout}] + (if (some? page) + [:> workspace-content* {:file file + :page page + :wglobal wglobal + :layout layout}] [:& workspace-loader*]))) +(def ^:private ref:file-without-data + (l/derived (fn [file] + (dissoc file :data)) + refs/file + =)) + (mf/defc workspace* {::mf/props :obj ::mf/wrap [mf/memo]} [{:keys [project-id file-id page-id layout-name]}] - (let [layout (mf/deref refs/workspace-layout) + (let [file-id (hooks/use-equal-memo file-id) + page-id (hooks/use-equal-memo page-id) + + layout (mf/deref refs/workspace-layout) wglobal (mf/deref refs/workspace-global) team (mf/deref refs/team) - file (mf/deref refs/workspace-file) + file (mf/deref ref:file-without-data) file-name (:name file) permissions (:permissions team) @@ -179,11 +181,10 @@ read-only? (mf/deref refs/workspace-read-only?) read-only? (or read-only? (not (:can-edit permissions))) - file-ready* (mf/with-memo [file-id] - (make-file-ready-ref file-id)) - file-ready? (mf/deref file-ready*) + ready* (mf/with-memo [file-id] + (make-workspace-ready-ref file-id)) + ready? (mf/deref ready*) - components-v2? (features/use-feature "components/v2") design-tokens? (features/use-feature "design-tokens/v1") background-color (:background-color wglobal)] @@ -206,21 +207,21 @@ (st/emit! ::dps/force-persist (dw/finalize-workspace file-id)))) - [:& (mf/provider ctx/current-project-id) {:value project-id} - [:& (mf/provider ctx/current-file-id) {:value file-id} - [:& (mf/provider ctx/current-page-id) {:value page-id} - [:& (mf/provider ctx/components-v2) {:value components-v2?} - [:& (mf/provider ctx/design-tokens) {:value design-tokens?} - [:& (mf/provider ctx/workspace-read-only?) {:value read-only?} + [:> (mf/provider ctx/current-project-id) {:value project-id} + [:> (mf/provider ctx/current-file-id) {:value file-id} + [:> (mf/provider ctx/current-page-id) {:value page-id} + [:> (mf/provider ctx/components-v2) {:value true} + [:> (mf/provider ctx/design-tokens) {:value design-tokens?} + [:> (mf/provider ctx/workspace-read-only?) {:value read-only?} [:> modal-container*] [:section {:class (stl/css :workspace) :style {:background-color background-color :touch-action "none"}} - [:& context-menu] + [:> context-menu*] - (if ^boolean file-ready? + (if ^boolean ready? [:> workspace-page* {:page-id page-id :file file :wglobal wglobal :layout layout}] - [:> workspace-loader* {}])]]]]]]])) + [:> workspace-loader*])]]]]]]])) diff --git a/frontend/src/app/main/ui/workspace/color_palette.cljs b/frontend/src/app/main/ui/workspace/color_palette.cljs index e1dfb52fa..6d4c2c9c9 100644 --- a/frontend/src/app/main/ui/workspace/color_palette.cljs +++ b/frontend/src/app/main/ui/workspace/color_palette.cljs @@ -24,29 +24,30 @@ [potok.v2.core :as ptk] [rumext.v2 :as mf])) -(mf/defc palette-item +(mf/defc palette-item* {::mf/wrap [mf/memo]} [{:keys [color size selected]}] - (letfn [(select-color [event] - (st/emit! - (dwl/add-recent-color color) - (mdc/apply-color-from-palette color (kbd/alt? event)) - (when (not= selected :recent) - (ptk/event - ::ev/event - {::ev/name "use-library-color" - ::ev/origin "color-palette" - :external-library (not= selected :file)}))))] - [:div {:class (stl/css-case :color-cell true - :is-not-library-color (nil? (:id color)) - :no-text (<= size 64)) + (let [select-color + (mf/use-fn + (mf/deps color selected) + (fn [event] + (st/emit! (dwl/add-recent-color color) + (mdc/apply-color-from-palette color (kbd/alt? event)) + (when (not= selected :recent) + (ptk/data-event ::ev/event + {::ev/name "use-library-color" + ::ev/origin "color-palette" + :external-library (not= selected :file)})))))] + [:div {:class (stl/css-case + :color-cell true + :is-not-library-color (nil? (:id color)) + :no-text (<= size 64)) :title (uc/get-color-name color) :on-click select-color} [:& cb/color-bullet {:color color}] [:& cb/color-name {:color color :size size :origin :palette}]])) - -(mf/defc palette +(mf/defc palette* [{:keys [current-colors size width selected]}] (let [;; We had to do this due to a bug that leave some bugged colors current-colors (h/use-equal-memo (filter #(or (:gradient %) (:color %) (:image %)) current-colors)) @@ -140,7 +141,7 @@ :max-width (str width "px") :right (str (* offset-step offset) "px")}} (for [[idx item] (map-indexed vector current-colors)] - [:& palette-item {:color item :key idx :size size :selected selected}])])] + [:> palette-item* {:color item :key idx :size size :selected selected}])])] (when show-arrows? [:button {:class (stl/css :right-arrow) :disabled (= offset max-offset) @@ -155,7 +156,7 @@ (mf/defc color-palette {::mf/wrap [mf/memo]} [{:keys [size width selected] :as props}] - (let [recent-colors (mf/deref refs/workspace-recent-colors) + (let [recent-colors (mf/deref refs/recent-colors) file-colors (mf/deref refs/workspace-file-colors) shared-libs (mf/deref refs/libraries) colors (mf/use-state [])] @@ -176,7 +177,7 @@ (reset! colors (into [] (->> (vals file-colors) (sort-by :name)))))) - [:& palette {:current-colors @colors - :size size - :width width - :selected selected}])) + [:> palette* {:current-colors @colors + :size size + :width width + :selected selected}])) diff --git a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs index 33f98effb..32f745165 100644 --- a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs +++ b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs @@ -17,7 +17,7 @@ (mf/defc color-palette-ctx-menu [{:keys [show-menu? close-menu on-select-palette selected]}] - (let [recent-colors (mf/deref refs/workspace-recent-colors) + (let [recent-colors (mf/deref refs/recent-colors) file-colors (mf/deref refs/workspace-file-colors) shared-libs (mf/deref refs/libraries)] [:& dropdown {:show show-menu? diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index 22524b678..4ce65154d 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -32,7 +32,7 @@ shared-libs (mf/deref refs/libraries) file-colors (mf/deref refs/workspace-file-colors) - recent-colors (mf/deref refs/workspace-recent-colors) + recent-colors (mf/deref refs/recent-colors) recent-colors (h/use-equal-memo (filter #(or (:gradient %) (:color %) (:image %)) recent-colors)) on-library-change diff --git a/frontend/src/app/main/ui/workspace/comments.cljs b/frontend/src/app/main/ui/workspace/comments.cljs index 2d416ebcc..376a91eee 100644 --- a/frontend/src/app/main/ui/workspace/comments.cljs +++ b/frontend/src/app/main/ui/workspace/comments.cljs @@ -73,9 +73,8 @@ [:span {:class (stl/css :icon)} i/tick]]])) (mf/defc comments-sidebar* - {::mf/props :obj} [{:keys [profiles threads page-id from-viewer]}] - (let [threads-map (mf/deref refs/threads-ref) + (let [threads-map (mf/deref refs/threads) profile (mf/deref refs/profile) profiles' (mf/deref refs/profiles) profiles (or profiles profiles') diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index dbbcbd066..60eab7916 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -748,7 +748,7 @@ ;; FIXME: optimize because it is rendered always -(mf/defc context-menu +(mf/defc context-menu* [] (let [mdata (mf/deref menu-ref) top (- (get-in mdata [:position :y]) 20) diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index 872f7d8db..ce1daca56 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -29,6 +29,7 @@ [app.main.ui.components.link-button :as lb] [app.main.ui.components.search-bar :refer [search-bar]] [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] @@ -38,7 +39,6 @@ [app.util.strings :refer [matches-search]] [beicon.v2.core :as rx] [cuerdas.core :as str] - [okulary.core :as l] [rumext.v2 :as mf])) (def ^:private close-icon @@ -53,25 +53,47 @@ (def ^:private library-icon (i/icon-xref :library (stl/css :library-icon))) -(def ref:workspace-file - (l/derived :workspace-file st/state)) +(defn- get-library-summary + "Given a library data return a summary representation of this library" + [data] + (let [colors (count (:colors data)) + graphics 0 + typographies (count (:typographies data)) + components (count (ctkl/components-seq data)) + empty? (and (zero? components) + (zero? graphics) + (zero? colors) + (zero? typographies))] -(defn create-file-library-ref - [library-id] - (letfn [(getter-fn [state] - (let [fdata (let [{:keys [id] :as wfile} (:workspace-data state)] - (if (= id library-id) - wfile - (dm/get-in state [:libraries library-id :data])))] - {:colors (-> fdata :colors vals) - :media (-> fdata :media vals) - :components (ctkl/components-seq fdata) - :typographies (-> fdata :typographies vals)}))] - (l/derived getter-fn st/state =))) + {:is-empty empty? + :colors colors + :graphics graphics + :typographies typographies + :components components})) + +(defn- adapt-backend-summary + [summary] + (let [components (or (-> summary :components :count) 0) + graphics (or (-> summary :media :count) 0) + typographies (or (-> summary :typographies :count) 0) + colors (or (-> summary :colors :count) 0) + + empty? (and (zero? components) + (zero? graphics) + (zero? colors) + (zero? typographies))] + {:is-empty empty? + :components components + :graphics graphics + :typographies typographies + :colors colors})) (defn- describe-library [components-count graphics-count colors-count typography-count] - (let [all-zero? (and (zero? components-count) (zero? graphics-count) (zero? colors-count) (zero? typography-count))] + (let [all-zero? (and (zero? components-count) + (zero? graphics-count) + (zero? colors-count) + (zero? typography-count))] (str (str/join " · " (cond-> [] @@ -88,26 +110,31 @@ (conj (tr "workspace.libraries.typography" typography-count)))) "\u00A0"))) -(mf/defc describe-library-blocks* +(mf/defc library-description* {::mf/props :obj ::mf/private true} - [{:keys [components-count graphics-count colors-count typography-count]}] - [:* - (when (pos? components-count) - [:li {:class (stl/css :element-count)} - (tr "workspace.libraries.components" components-count)]) + [{:keys [summary]}] + (let [components-count (get summary :components) + graphics-count (get summary :graphics) + typography-count (get summary :typographies) + colors-count (get summary :colors)] - (when (pos? graphics-count) - [:li {:class (stl/css :element-count)} - (tr "workspace.libraries.graphics" graphics-count)]) + [:* + (when (pos? components-count) + [:li {:class (stl/css :element-count)} + (tr "workspace.libraries.components" components-count)]) - (when (pos? colors-count) - [:li {:class (stl/css :element-count)} - (tr "workspace.libraries.colors" colors-count)]) + (when (pos? graphics-count) + [:li {:class (stl/css :element-count)} + (tr "workspace.libraries.graphics" graphics-count)]) - (when (pos? typography-count) - [:li {:class (stl/css :element-count)} - (tr "workspace.libraries.typography" typography-count)])]) + (when (pos? colors-count) + [:li {:class (stl/css :element-count)} + (tr "workspace.libraries.colors" colors-count)]) + + (when (pos? typography-count) + [:li {:class (stl/css :element-count)} + (tr "workspace.libraries.typography" typography-count)])])) (mf/defc sample-library-entry* {::mf/props :obj @@ -146,26 +173,35 @@ :value (if (= importing? id) (tr "labels.adding") (tr "labels.add")) :on-click import-library}]])) +(defn- empty-library? + "Check if currentt library summary has elements or not" + [summary] + (let [colors (or (-> summary :colors :count) 0) + components (or (-> summary :components :count) 0) + media (or (-> summary :media :count) 0) + typographies (or (-> summary :typographies :count) 0)] + + (and (zero? colors) + (zero? components) + (zero? media) + (zero? typographies)))) + (mf/defc libraries-tab* {::mf/props :obj ::mf/private true} - [{:keys [file-id is-shared linked-libraries shared-libraries]}] - (let [search-term* (mf/use-state "") + [{:keys [is-shared linked-libraries shared-libraries]}] + (let [file-id (mf/use-ctx ctx/current-file-id) + search-term* (mf/use-state "") search-term (deref search-term*) - library-ref (mf/with-memo [file-id] - (create-file-library-ref file-id)) - library (deref library-ref) - colors (:colors library) - components (:components library) - media (:media library) - typographies (:typographies library) + + ;; The summary of the current/local library + ;; NOTE: we only need a snapshot of current library + local-library (deref refs/workspace-data) + summary (get-library-summary local-library) + empty-library? (empty-library? summary) + selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent) - empty-library? (and - (zero? (count colors)) - (zero? (count components)) - (zero? (count media)) - (zero? (count typographies))) shared-libraries (mf/with-memo [shared-libraries linked-libraries file-id search-term] @@ -263,10 +299,8 @@ [:div {:class (stl/css :item-content)} [:div {:class (stl/css :item-name)} (tr "workspace.libraries.file-library")] [:ul {:class (stl/css :item-contents)} - [:> describe-library-blocks* {:components-count (count components) - :graphics-count (count media) - :colors-count (count colors) - :typography-count (count typographies)}]]] + [:> library-description* {:summary summary}]]] + (if ^boolean is-shared [:input {:class (stl/css :item-unpublish) :type "button" @@ -277,21 +311,15 @@ :value (tr "common.publish") :on-click publish}])] - (for [{:keys [id name] :as library} linked-libraries] + (for [{:keys [id name data] :as library} linked-libraries] [:div {:class (stl/css :section-list-item) :key (dm/str id) :data-testid "library-item"} [:div {:class (stl/css :item-content)} [:div {:class (stl/css :item-name)} name] [:ul {:class (stl/css :item-contents)} - (let [components-count (count (or (ctkl/components-seq (:data library)) [])) - graphics-count (count (dm/get-in library [:data :media] [])) - colors-count (count (dm/get-in library [:data :colors] [])) - typography-count (count (dm/get-in library [:data :typographies] []))] - [:> describe-library-blocks* {:components-count components-count - :graphics-count graphics-count - :colors-count colors-count - :typography-count typography-count}])]] + (let [summary (get-library-summary data)] + [:> library-description* {:summary summary}])]] [:button {:class (stl/css :item-button) :type "button" @@ -318,14 +346,10 @@ [:div {:class (stl/css :item-content)} [:div {:class (stl/css :item-name)} name] [:ul {:class (stl/css :item-contents)} - (let [components-count (dm/get-in library [:library-summary :components :count] 0) - graphics-count (dm/get-in library [:library-summary :media :count] 0) - colors-count (dm/get-in library [:library-summary :colors :count] 0) - typography-count (dm/get-in library [:library-summary :typographies :count] 0)] - [:> describe-library-blocks* {:components-count components-count - :graphics-count graphics-count - :colors-count colors-count - :typography-count typography-count}])]] + (let [summary (-> (:library-summary library) + (adapt-backend-summary))] + [:> library-description* {:summary summary}])]] + [:button {:class (stl/css :item-button-shared) :data-library-id (dm/str id) :title (tr "workspace.libraries.shared-library-btn") @@ -414,11 +438,16 @@ (mf/defc updates-tab* {::mf/props :obj ::mf/private true} - [{:keys [file-id file-data libraries]}] + [{:keys [file-id libraries]}] + ;; FIXME: naming (let [summary?* (mf/use-state true) summary? (deref summary?*) updating? (mf/deref refs/updating-library) + ;; NOTE: we don't want to react on file changes, we just want + ;; a snapshot of file on the momento of open the dialog + file-data (deref refs/workspace-data) + see-all-assets (mf/use-fn (fn [] @@ -544,22 +573,31 @@ (when (or (pos? (:components exceeded)) (pos? (:colors exceeded)) (pos? (:typographies exceeded))) - [:& lb/link-button {:on-click see-all-assets - :class (stl/css :libraries-updates-see-all) - :value (str "(" (tr "workspace.libraries.update.see-all-changes") ")")}])])]])]])) + [:& lb/link-button + {:on-click see-all-assets + :class (stl/css :libraries-updates-see-all) + :value (str "(" (tr "workspace.libraries.update.see-all-changes") ")")}])])]])]])) + (mf/defc libraries-dialog {::mf/register modal/components ::mf/register-as :libraries-dialog} [{:keys [starting-tab] :as props :or {starting-tab :libraries}}] - (let [file-data (mf/deref refs/workspace-data) - file (mf/deref ref:workspace-file) + (let [;; NOTE: we don't want to react on file changes, we just want + ;; a snapshot of file on the momento of open the dialog + file (deref refs/file) file-id (:id file) shared? (:is-shared file) - libraries (mf/deref refs/libraries) - libraries (mf/with-memo [libraries] - (d/removem (fn [[_ val]] (:is-indirect val)) libraries)) + linked-libraries + (mf/deref refs/files) + + linked-libraries + (mf/with-memo [linked-libraries file-id] + (d/removem (fn [[_ lib]] + (or (:is-indirect lib) + (= (:id lib) file-id))) + linked-libraries)) shared-libraries (mf/deref refs/shared-files) @@ -578,16 +616,14 @@ libraries-tab (mf/html [:> libraries-tab* - {:file-id file-id - :is-shared shared? - :linked-libraries libraries + {:is-shared shared? + :linked-libraries linked-libraries :shared-libraries shared-libraries}]) updates-tab (mf/html [:> updates-tab* {:file-id file-id - :file-data file-data - :libraries libraries}]) + :libraries linked-libraries}]) tabs #js [#js {:label (tr "workspace.libraries.libraries") @@ -600,7 +636,9 @@ (mf/with-effect [] (st/emit! (dtm/fetch-shared-files))) - [:div {:class (stl/css :modal-overlay) :on-click close-dialog-outside :data-testid "libraries-modal"} + [:div {:class (stl/css :modal-overlay) + :on-click close-dialog-outside + :data-testid "libraries-modal"} [:div {:class (stl/css :modal-dialog)} [:button {:class (stl/css :close-btn) :on-click close-dialog diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 346c5616b..5eb392327 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -11,7 +11,7 @@ [app.common.geom.shapes.bounds :as gsb] [app.common.math :as mth] [app.common.thumbnails :as thc] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [app.main.data.workspace.thumbnails :as dwt] [app.main.refs :as refs] [app.main.store :as st] @@ -70,7 +70,7 @@ ::mf/wrap-props false} [props] (let [shape (unchecked-get props "shape") - objects (wsh/lookup-page-objects @st/state) + objects (dsh/lookup-page-objects @st/state) frame-id (dm/get-prop shape :id) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index 111ec3cdc..893ac6317 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -20,10 +20,11 @@ [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.assets.common :as cmm] - [app.main.ui.workspace.sidebar.assets.file-library :refer [file-library]] + [app.main.ui.workspace.sidebar.assets.file-library :refer [file-library*]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] + [okulary.core :as l] [rumext.v2 :as mf])) (mf/defc assets-libraries* @@ -31,38 +32,39 @@ ::mf/props :obj ::mf/private true} [{:keys [filters]}] - (let [libraries (mf/deref refs/libraries) - libraries (mf/with-memo [libraries] + (let [file-id (mf/use-ctx ctx/current-file-id) + + libraries (mf/deref refs/libraries) + libraries (mf/with-memo [libraries file-id] (->> (vals libraries) (remove :is-indirect) + (remove #(= file-id (:id %))) (map (fn [file] (update file :data dissoc :pages-index))) (sort-by #(str/lower (:name %)))))] + (for [file libraries] - [:& file-library + [:> file-library* {:key (dm/str (:id file)) :file file - :local? false - :default-open? false + :is-local false + :is-default-open false :filters filters}]))) +(def ^:private ref:local-library + (l/derived (fn [file] + (update file :data dissoc :pages-index)) + refs/file)) + (mf/defc assets-local-library {::mf/wrap [mf/memo] ::mf/wrap-props false} [{:keys [filters]}] - ;; NOTE: as workspace-file is an incomplete view of file (it do not - ;; contain :data), we need to reconstruct it using workspace-data - (let [file (mf/deref refs/workspace-file) - data (mf/deref refs/workspace-data) - data (mf/with-memo [data] - (dissoc data :pages-index)) - file (mf/with-memo [file data] - (assoc file :data data))] - - [:& file-library + (let [file (mf/deref ref:local-library)] + [:> file-library* {:file file - :local? true - :default-open? true + :is-local true + :is-default-open true :filters filters}])) (defn- toggle-values diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs index 9b20a62b3..371cfc624 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs @@ -15,6 +15,7 @@ [app.common.types.container :as ctn] [app.common.types.file :as ctf] [app.config :as cf] + [app.main.data.helpers :as dsh] [app.main.data.modal :as modal] [app.main.data.workspace :as dw] [app.main.data.workspace.libraries :as dwl] @@ -58,7 +59,10 @@ (if reverse? "z" "a") path)] (str/lower (cfh/merge-path-item path name)))) - (if ^boolean reverse? > <))))) + (if ^boolean reverse? > <)) + + :always + (vec)))) (defn add-group [asset group-name] @@ -315,10 +319,13 @@ copies (filter ctk/in-component-copy? shapes) current-file-id (mf/use-ctx ctx/current-file-id) - objects (deref refs/workspace-page-objects) - workspace-data (deref refs/workspace-data) + current-page-id (mf/use-ctx ctx/current-page-id) + libraries (deref refs/libraries) - current-file {:id current-file-id :data workspace-data} + current-file (get libraries current-file-id) + + objects (-> (dsh/get-page (:data current-file) current-page-id) + (get :objects)) find-component (fn [shape include-deleted?] (ctf/resolve-component diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs index f94ebbb4c..dd2c00737 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs @@ -37,31 +37,23 @@ [potok.v2.core :as ptk] [rumext.v2 :as mf])) -(def drag-data* (atom {:local? false})) +(def drag-data* (atom {:is-local false})) (defn set-drag-data! [data] (reset! drag-data* data)) (defn- get-component-root-and-container - [file-id component components-v2] - (if (= file-id (:id @refs/workspace-file)) - (let [data @refs/workspace-data] - [(ctf/get-component-root data component) - (if components-v2 - (ctf/get-component-page data component) - component)]) - (let [data (dm/get-in @refs/libraries [file-id :data]) - root-shape (ctf/get-component-root data component) - container (if components-v2 - (ctf/get-component-page data component) - component)] - [root-shape container]))) + [file-id component] + (let [data (dm/get-in @refs/libraries [file-id :data]) + root-shape (ctf/get-component-root data component) + container (ctf/get-component-page data component)] + [root-shape container])) (mf/defc components-item {::mf/wrap-props false} [{:keys [component renaming listing-thumbs? selected file-id on-asset-click on-context-menu on-drag-start do-rename - cancel-rename selected-full selected-paths local]}] + cancel-rename selected-full selected-paths is-local]}] (let [item-ref (mf/use-ref) @@ -69,7 +61,6 @@ dragging? (deref dragging*) read-only? (mf/use-ctx ctx/workspace-read-only?) - components-v2 (mf/use-ctx ctx/components-v2) component-id (:id component) visible? (h/use-visible item-ref :once? true) @@ -78,7 +69,7 @@ ;; really need rerender on any change on the file change. If ;; the component changes, it will trigger rerender anyway. [root-shape container] - (get-component-root-and-container file-id component components-v2) + (get-component-root-and-container file-id component) unselect-all (mf/use-fn @@ -94,38 +85,38 @@ on-component-double-click (mf/use-fn - (mf/deps file-id component local) + (mf/deps file-id component is-local) (fn [event] (dom/stop-propagation event) - (if local + (if is-local (st/emit! (dwl/go-to-local-component component-id)) (st/emit! (dwl/go-to-component-file file-id component))))) on-drop (mf/use-fn - (mf/deps component dragging* selected selected-full selected-paths local drag-data*) + (mf/deps component dragging* selected selected-full selected-paths is-local drag-data*) (fn [event] - (when (and local (:local? @drag-data*)) + (when (and is-local (:is-local @drag-data*)) (cmm/on-drop-asset event component dragging* selected selected-full selected-paths dwl/rename-component-and-main-instance)))) on-drag-enter (mf/use-fn - (mf/deps component dragging* selected selected-paths local drag-data*) + (mf/deps component dragging* selected selected-paths is-local drag-data*) (fn [event] - (when (and local (:local? @drag-data*)) + (when (and is-local (:is-local @drag-data*)) (cmm/on-drag-enter-asset event component dragging* selected selected-paths)))) on-drag-leave (mf/use-fn - (mf/deps dragging* local drag-data*) + (mf/deps dragging* is-local drag-data*) (fn [event] - (when (and local (:local? @drag-data*)) + (when (and is-local (:is-local @drag-data*)) (cmm/on-drag-leave-asset event dragging*)))) on-component-drag-start (mf/use-fn - (mf/deps file-id component selected item-ref on-drag-start read-only? local) + (mf/deps file-id component selected item-ref on-drag-start read-only? is-local) (fn [event] (if read-only? (dom/prevent-default event) @@ -183,7 +174,7 @@ {::mf/wrap-props false} [{:keys [file-id prefix groups open-groups force-open? renaming listing-thumbs? selected on-asset-click on-drag-start do-rename cancel-rename on-rename-group on-group on-ungroup on-context-menu - selected-full local]}] + selected-full is-local]}] (let [group-open? (if (false? (get open-groups prefix)) ;; if the user has closed it specifically, respect that false @@ -199,23 +190,23 @@ selected-full)) on-drag-enter (mf/use-fn - (mf/deps dragging* prefix selected-paths local drag-data*) + (mf/deps dragging* prefix selected-paths is-local drag-data*) (fn [event] - (when (and local (:local? @drag-data*)) + (when (and is-local (:is-local @drag-data*)) (cmm/on-drag-enter-asset-group event dragging* prefix selected-paths)))) on-drag-leave (mf/use-fn - (mf/deps dragging* local drag-data*) + (mf/deps dragging* is-local drag-data*) (fn [event] - (when (and local (:local? @drag-data*)) + (when (and is-local (:is-local @drag-data*)) (cmm/on-drag-leave-asset event dragging*)))) on-drop (mf/use-fn - (mf/deps dragging* prefix selected-paths selected-full local drag-data*) + (mf/deps dragging* prefix selected-paths selected-full is-local drag-data*) (fn [event] - (when (and local (:local? @drag-data*)) + (when (and is-local (:is-local @drag-data*)) (cmm/on-drop-asset-group event dragging* prefix selected-paths selected-full dwl/rename-component-and-main-instance))))] [:div {:class (stl/css :component-group) @@ -248,7 +239,7 @@ (when (and (empty? components) (some? groups) - local) + is-local) [:div {:class (stl/css-case :drop-space true :drop-space-small (not dragging?))}]) @@ -268,7 +259,7 @@ :on-group on-group :do-rename do-rename :cancel-rename cancel-rename - :local local}])]) + :is-local is-local}])]) (for [[path-item content] groups] (when-not (empty? path-item) @@ -289,11 +280,11 @@ :on-ungroup on-ungroup :on-context-menu on-context-menu :selected-full selected-full - :local local}]))])])) + :is-local is-local}]))])])) (mf/defc components-section {::mf/wrap-props false} - [{:keys [file-id local? components listing-thumbs? open? force-open? + [{:keys [file-id is-local components listing-thumbs? open? force-open? reverse-sort? selected on-asset-click on-assets-delete on-clear-selection open-status-ref]}] @@ -466,7 +457,7 @@ (fn [component event] (let [file-data - (d/nilv (dm/get-in @refs/libraries [file-id :data]) @refs/workspace-data) + (dm/get-in @refs/libraries [file-id :data]) shape-main (ctf/get-component-root file-data component)] @@ -476,7 +467,7 @@ (set-drag-data! {:file-id file-id :component component :shape shape-main - :local? local?}) + :is-local is-local}) (dnd/set-data! event "penpot/component" true) @@ -487,10 +478,10 @@ on-show-main (mf/use-fn - (mf/deps current-component-id file-id local?) + (mf/deps current-component-id file-id is-local) (fn [event] (dom/stop-propagation event) - (if local? + (if is-local (st/emit! (dwl/go-to-local-component :id current-component-id)) (let [component (d/seek #(= (:id %) current-component-id) components)] (st/emit! (dwl/go-to-component-file file-id component)))))) @@ -518,7 +509,7 @@ :title (tr "workspace.assets.grid-view") :id "opt-grid"}]]]) - (when (and components-v2 (not read-only?) local?) + (when (and components-v2 (not read-only?) is-local) [:> icon-button* {:variant "ghost" :aria-label (tr "workspace.assets.components.add-component") :on-click add-component @@ -547,27 +538,27 @@ :on-ungroup on-ungroup :on-context-menu on-context-menu :selected-full selected-full - :local ^boolean local?}]) + :local ^boolean is-local}]) [:& cmm/assets-context-menu {:on-close on-close-menu :state @menu-state - :options [(when (and local? (not (or multi-components? multi-assets? read-only?))) + :options [(when (and is-local (not (or multi-components? multi-assets? read-only?))) {:name (tr "workspace.assets.rename") :id "assets-rename-component" :handler on-rename}) - (when (and local? (not (or multi-assets? read-only?))) + (when (and is-local (not (or multi-assets? read-only?))) {:name (if components-v2 (tr "workspace.assets.duplicate-main") (tr "workspace.assets.duplicate")) :id "assets-duplicate-component" :handler on-duplicate}) - (when (and local? (not read-only?)) + (when (and is-local (not read-only?)) {:name (tr "workspace.assets.delete") :id "assets-delete-component" :handler on-delete}) - (when (and local? (not (or multi-assets? read-only?))) + (when (and is-local (not (or multi-assets? read-only?))) {:name (tr "workspace.assets.group") :id "assets-group-component" :handler on-group}) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs index d069ae416..d707cd053 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs @@ -9,6 +9,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.types.components-list :as ctkl] [app.main.data.event :as ev] [app.main.data.workspace :as dw] [app.main.data.workspace.libraries :as dwl] @@ -19,7 +20,6 @@ [app.main.ui.components.title-bar :refer [title-bar]] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.main.ui.workspace.libraries :refer [create-file-library-ref]] [app.main.ui.workspace.sidebar.assets.colors :refer [colors-section]] [app.main.ui.workspace.sidebar.assets.common :as cmm] [app.main.ui.workspace.sidebar.assets.components :refer [components-section]] @@ -33,6 +33,10 @@ [potok.v2.core :as ptk] [rumext.v2 :as mf])) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; REFS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (def ^:private ref:open-status (l/derived (l/in [:workspace-assets :open-status]) st/state)) @@ -40,8 +44,37 @@ (-> (l/in [:workspace-assets :selected]) (l/derived st/state))) +(defn- create-file-ref + [library-id] + (l/derived (fn [state] + (dm/get-in state [:files library-id :data])) + st/state)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; LOCAL HELPER HOOKS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn- use-library-ref + [file-id] + (let [library-ref (mf/with-memo [file-id] + (create-file-ref file-id))] + (mf/deref library-ref))) + +(defn- use-selected + "Returns the currently selected assets set on the library" + [file-id] + (let [selected-ref + (mf/with-memo [file-id] + (-> (l/key file-id) + (l/derived ref:selected)))] + (mf/deref selected-ref))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; COMPONENTS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (mf/defc file-library-title* - {::mf/props :obj} + {::mf/private true} [{:keys [is-open is-local file-id page-id file-name]}] (let [router (mf/deref refs/router) team-id (mf/use-ctx ctx/current-team-id) @@ -61,8 +94,9 @@ (dom/stop-propagation ev) (st/emit! (ptk/data-event ::ev/event {::ev/name "navigate-to-library-file"}))))] - [:div {:class (stl/css-case :library-title true - :open is-open)} + [:div {:class (stl/css-case + :library-title true + :open is-open)} [:& title-bar {:collapsable true :collapsed (not is-open) :all-clickable true @@ -71,10 +105,9 @@ (mf/html [:div {:class (stl/css :special-title)} (tr "workspace.assets.local-library")]) ;; Do we need to add shared info here? - (mf/html [:div {:class (stl/css :special-title)} file-name]))} - (when-not is-local + (when-not ^boolean is-local [:span {:title (tr "workspace.assets.open-library")} [:a {:class (stl/css :file-link) :href (str "#" url) @@ -82,102 +115,87 @@ :on-click on-click} i/open-link]])]])) -(mf/defc file-library-content - {::mf/wrap-props false} - [{:keys [file local? open-status-ref on-clear-selection filters]}] - (let [components-v2 (mf/use-ctx ctx/components-v2) - open-status (mf/deref open-status-ref) +(defn- extend-selected + [selected type asset-groups asset-id file-id] + (letfn [(flatten-groups [groups] + (reduce concat [(get groups "" []) + (into [] + (->> (filter #(seq (first %)) groups) + (map second) + (mapcat flatten-groups)))]))] - file-id (:id file) - project-id (:project-id file) + (let [selected' (get selected type)] + (if (zero? (count selected')) + (st/emit! (dw/select-single-asset file-id asset-id type)) + (let [all-assets (flatten-groups asset-groups) + click-index (d/index-of-pred all-assets #(= (:id %) asset-id)) + first-index (->> (get selected type) + (map (fn [asset] (d/index-of-pred all-assets #(= (:id %) asset)))) + (sort) + (first)) - filters-section (:section filters) + min-index (min first-index click-index) + max-index (max first-index click-index) + ids (->> (d/enumerate all-assets) + (into #{} (comp (filter #(<= min-index (first %) max-index)) + (map (comp :id second)))))] - filters-term (:term filters) - filters-ordering (:ordering filters) - filters-list-style (:list-style filters) + (st/emit! (dw/select-assets file-id ids type))))))) - reverse-sort? (= :desc filters-ordering) - listing-thumbs? (= :thumbs filters-list-style) +(mf/defc file-library-content* + {::mf/private true} + [{:keys [file is-local open-status-ref on-clear-selection filters colors media typographies components]}] + (let [open-status (mf/deref open-status-ref) - library-ref (mf/with-memo [file-id] - (create-file-library-ref file-id)) + file-id (:id file) + project-id (:project-id file) - library (mf/deref library-ref) - colors (:colors library) - components (:components library) - media (:media library) - typographies (:typographies library) + filters-section (:section filters) + has-filters-term? (not ^boolean (str/empty? (:term filters))) - colors (mf/with-memo [filters colors] - (cmm/apply-filters colors filters)) - components (mf/with-memo [filters components] - (cmm/apply-filters components filters)) - media (mf/with-memo [filters media] - (cmm/apply-filters media filters)) - typographies (mf/with-memo [filters typographies] - (cmm/apply-filters typographies filters)) + reverse-sort? (= :desc (:ordering filters)) + listing-thumbs? (= :thumbs (:list-style filters)) - show-components? (and (or (= filters-section "all") - (= filters-section "components")) - (or (pos? (count components)) - (str/empty? filters-term))) - show-graphics? (and (or (= filters-section "all") - (= filters-section "graphics")) - (or (pos? (count media)) - (and (str/empty? filters-term) - (not components-v2)))) - show-colors? (and (or (= filters-section "all") - (= filters-section "colors")) - (or (> (count colors) 0) - (str/empty? filters-term))) - show-typography? (and (or (= filters-section "all") - (= filters-section "typographies")) - (or (pos? (count typographies)) - (str/empty? filters-term))) + selected (use-selected file-id) - selected-lens (mf/with-memo [file-id] - (-> (l/key file-id) - (l/derived ref:selected))) + show-components? + (and (or (= filters-section "all") + (= filters-section "components")) + (or (pos? (count components)) + (not has-filters-term?))) - selected (mf/deref selected-lens) + show-graphics? + (and (or (= filters-section "all") + (= filters-section "graphics")) + (pos? (count media))) - has-term? (not ^boolean (str/empty? filters-term)) - force-open-components? (when ^boolean has-term? (> 60 (count components))) - force-open-colors? (when ^boolean has-term? (> 60 (count colors))) - force-open-graphics? (when ^boolean has-term? (> 60 (count media))) - force-open-typographies? (when ^boolean has-term? (> 60 (count typographies))) + show-colors? + (and (or (= filters-section "all") + (= filters-section "colors")) + (or (> (count colors) 0) + (not has-filters-term?))) - extend-selected - (fn [type asset-groups asset-id] - (letfn [(flatten-groups [groups] - (reduce concat [(get groups "" []) - (into [] - (->> (filter #(seq (first %)) groups) - (map second) - (mapcat flatten-groups)))]))] + show-typography? + (and (or (= filters-section "all") + (= filters-section "typographies")) + (or (pos? (count typographies)) + (not has-filters-term?))) - (let [selected' (get selected type)] - (if (zero? (count selected')) - (st/emit! (dw/select-single-asset file-id asset-id type)) - (let [all-assets (flatten-groups asset-groups) - click-index (d/index-of-pred all-assets #(= (:id %) asset-id)) - first-index (->> (get selected type) - (map (fn [asset] (d/index-of-pred all-assets #(= (:id %) asset)))) - (sort) - (first)) + force-open-components? + (when ^boolean has-filters-term? (> 60 (count components))) - min-index (min first-index click-index) - max-index (max first-index click-index) - ids (->> (d/enumerate all-assets) - (into #{} (comp (filter #(<= min-index (first %) max-index)) - (map (comp :id second)))))] + force-open-colors? + (when ^boolean has-filters-term? (> 60 (count colors))) - (st/emit! (dw/select-assets file-id ids type))))))) + force-open-graphics? + (when ^boolean has-filters-term? (> 60 (count media))) + + force-open-typographies? + (when ^boolean has-filters-term? (> 60 (count typographies))) on-asset-click (mf/use-fn - (mf/deps file-id extend-selected) + (mf/deps file-id selected) (fn [asset-type asset-groups asset-id default-click event] (cond (kbd/mod? event) @@ -188,7 +206,7 @@ (kbd/shift? event) (do (dom/stop-propagation event) - (extend-selected asset-type asset-groups asset-id)) + (extend-selected selected asset-type asset-groups asset-id file-id)) :else (when default-click @@ -232,7 +250,7 @@ (when ^boolean show-components? [:& components-section {:file-id file-id - :local? local? + :local? is-local :components components :listing-thumbs? listing-thumbs? :open? (or ^boolean force-open-components? @@ -249,7 +267,7 @@ [:& graphics-section {:file-id file-id :project-id project-id - :local? local? + :local? is-local :objects media :listing-thumbs? listing-thumbs? :open? (or ^boolean force-open-graphics? @@ -265,7 +283,7 @@ (when ^boolean show-colors? [:& colors-section {:file-id file-id - :local? local? + :local? is-local :colors colors :open? (or ^boolean force-open-colors? ^boolean (get open-status :colors false)) @@ -281,7 +299,7 @@ [:& typographies-section {:file file :file-id (:id file) - :local? local? + :local? is-local :typographies typographies :open? (or ^boolean force-open-typographies? ^boolean (get open-status :typographies false)) @@ -303,67 +321,90 @@ [:span {:class (stl/css :no-found-text)} (tr "workspace.assets.not-found")]])])) -(defn- force-lib-open? [file-id filters] - (let [library-ref (mf/with-memo [file-id] - (create-file-library-ref file-id)) - library (mf/deref library-ref) +(mf/defc file-library* + [{:keys [file is-local is-default-open? filters]}] + (let [file-id (:id file) + file-name (:name file) + page-id (dm/get-in file [:data :pages 0]) - colors (:colors library) - components (:components library) - media (:media library) - typographies (:typographies library) + library (use-library-ref file-id) - filtered-colors (mf/with-memo [filters colors] - (cmm/apply-filters colors filters)) - filtered-components (mf/with-memo [filters components] - (cmm/apply-filters components filters)) - filtered-media (mf/with-memo [filters media] - (cmm/apply-filters media filters)) - filtered-typographies (mf/with-memo [filters typographies] - (cmm/apply-filters typographies filters)) + colors (:colors library) + media (:media library) + typographies (:typographies library) - filters-term (:term filters) - has-term? (not (str/blank? filters-term))] - (and has-term? - (some pos? (map count [filtered-components filtered-colors filtered-media filtered-typographies])) - (some #(> 60 (count %)) [filtered-components filtered-colors filtered-media filtered-typographies])))) + filters-term (:term filters) -(mf/defc file-library - {::mf/props :obj} - [{:keys [file local? default-open? filters]}] - (let [file-id (:id file) - file-name (:name file) - page-id (dm/get-in file [:data :pages 0]) + ;; FIXME: maybe unused + ;; has-term? (not (str/blank? filters-term)) - open-status-ref (mf/with-memo [file-id] - (-> (l/key file-id) - (l/derived ref:open-status))) - open-status (mf/deref open-status-ref) - force-open-lib? (force-lib-open? file-id filters) + filtered-colors + (mf/with-memo [filters colors] + (-> (vals colors) + (cmm/apply-filters filters))) - open? (if (false? (:library open-status)) ;; if the user has closed it specifically, respect that - false - (or force-open-lib? - (d/nilv (:library open-status) default-open?))) + filtered-components + (mf/with-memo [filters library] + (-> (into [] (ctkl/components-seq library)) + (cmm/apply-filters filters))) + + filtered-media + (mf/with-memo [filters media] + (-> (vals media) + (cmm/apply-filters filters))) + + filtered-typographies + (mf/with-memo [filters typographies] + (-> (vals typographies) + (cmm/apply-filters filters))) + + open-status-ref + (mf/with-memo [file-id] + (-> (l/key file-id) + (l/derived ref:open-status))) + + open-status + (mf/deref open-status-ref) + + force-lib-open? + (and (not (str/blank? filters-term)) + (or (> 60 (count filtered-colors)) + (> 60 (count filtered-components)) + (> 60 (count filtered-media)) + (> 60 (count filtered-typographies)))) + + open? + (if (false? (:library open-status)) + ;; if the user has closed it specifically, respect that + false + (or force-lib-open? + (d/nilv (:library open-status) is-default-open?))) unselect-all (mf/use-fn (mf/deps file-id) (fn [] (st/emit! (dw/unselect-all-assets file-id))))] + [:div {:class (stl/css :tool-window) :on-context-menu dom/prevent-default :on-click unselect-all} + [:> file-library-title* {:file-id file-id :page-id page-id :file-name file-name :is-open open? - :is-local local?}] + :is-local is-local}] + (when ^boolean open? - [:& file-library-content + [:> file-library-content* {:file file - :local? local? + :is-local is-local :filters filters + :colors filtered-colors + :components filtered-components + :media filtered-media + :typographies filtered-typographies :on-clear-selection unselect-all :open-status-ref open-status-ref}])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs index ecb553e0c..bfbf3092e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs @@ -249,6 +249,7 @@ read-only? (mf/use-ctx ctx/workspace-read-only?) menu-state (mf/use-state cmm/initial-context-menu-state) + typographies (mf/with-memo [typographies] (mapv dwl/extract-path-if-missing typographies)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 491b86707..563cf39a8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -169,11 +169,12 @@ (defn use-search [page objects] (let [state* (mf/use-state - {:show-search false - :show-menu false - :search-text "" - :filters #{} - :num-items 100}) + #(do {:show-search false + :show-menu false + :search-text "" + :filters #{} + :num-items 100})) + state (deref state*) current-filters (:filters state) current-items (:num-items state) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs index fd095088a..86fb956a2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs @@ -268,15 +268,6 @@ [:span {:class (stl/css :arrow-icon)} i/arrow]])) -(def ^:private ref:swap-libraries - (letfn [(get-libraries [state] - (let [file (:workspace-file state) - data (:workspace-data state) - libs (:libraries state)] - (assoc libs (:id file) - (assoc file :data data))))] - (l/derived get-libraries st/state))) - (defn- find-common-path ([components] (let [paths (map (comp cfh/split-path :path) components)] @@ -298,14 +289,13 @@ (= (:component-id shape-a) (:component-id shape-b))) - (mf/defc component-swap {::mf/props :obj} [{:keys [shapes]}] (let [single? (= 1 (count shapes)) shape (first shapes) current-file-id (mf/use-ctx ctx/current-file-id) - libraries (mf/deref ref:swap-libraries) + libraries (mf/deref refs/files) objects (mf/deref refs/workspace-page-objects) ^boolean @@ -522,12 +512,13 @@ {::mf/props :obj} [{:keys [shapes swap-opened?]}] (let [current-file-id (mf/use-ctx ctx/current-file-id) - components-v2 (mf/use-ctx ctx/components-v2) - workspace-data (deref refs/workspace-data) - libraries (deref refs/libraries) - state* (mf/use-state {:show-content true - :menu-open false}) + libraries (deref refs/libraries) + current-file (get libraries current-file-id) + + state* (mf/use-state + #(do {:show-content true + :menu-open false})) state (deref state*) open? (:show-content state) menu-open? (:menu-open state) @@ -535,18 +526,18 @@ shapes (filter ctk/instance-head? shapes) multi (> (count shapes) 1) copies (filter ctk/in-component-copy? shapes) - can-swap? (and components-v2 (seq copies)) + can-swap? (boolean (seq copies)) ;; For when it's only one shape shape (first shapes) id (:id shape) shape-name (:name shape) + component (ctf/resolve-component shape - {:id current-file-id - :data workspace-data} + current-file libraries {:include-deleted? true}) - main-instance? (if components-v2 (ctk/main-instance? shape) true) + main-instance? (ctk/main-instance? shape) toggle-content (mf/use-fn #(swap! state* update :show-content not)) @@ -585,7 +576,7 @@ (fn [] (swap! state* update :render inc))) - menu-entries (cmm/generate-components-menu-entries shapes components-v2) + menu-entries (cmm/generate-components-menu-entries shapes true) show-menu? (seq menu-entries) path (->> component (:path) (cfh/split-path) (cfh/join-path-with-dot))] @@ -650,7 +641,7 @@ (when swap-opened? [:& component-swap {:shapes copies}]) - (when (and (not swap-opened?) (not multi) components-v2) + (when (and (not swap-opened?) (not multi)) [:& component-annotation {:id id :shape shape :component component :rerender-fn rerender-fn}]) (when (dbg/enabled? :display-touched) [:div ":touched " (str (:touched shape))])])]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs index fa49570e0..dd8908d76 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs @@ -9,8 +9,8 @@ (:require [app.common.data :as d] [app.main.data.exports.assets :as de] + [app.main.data.helpers :as dsh] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.select :refer [select]] @@ -40,7 +40,7 @@ state (mf/deref refs/export) in-progress? (:in-progress state) - shapes-with-exports (->> (wsh/lookup-shapes @st/state ids) + shapes-with-exports (->> (dsh/lookup-shapes @st/state ids) (filter #(pos? (count (:exports %))))) sname (when (seqable? exports) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs index b8d832f8b..f4c3971ec 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs @@ -9,6 +9,7 @@ (:require [app.common.colors :as clr] [app.common.data :as d] + [app.common.types.color :as ctc] [app.common.types.shape.attrs :refer [default-color]] [app.main.data.workspace.colors :as dc] [app.main.store :as st] @@ -167,12 +168,7 @@ (seq fills) [:& h/sortable-container {} (for [[index value] (d/enumerate (:fills values []))] - [:& color-row {:color {:color (:fill-color value) - :opacity (:fill-opacity value) - :id (:fill-color-ref-id value) - :file-id (:fill-color-ref-file value) - :gradient (:fill-color-gradient value) - :image (:fill-image value)} + [:& color-row {:color (ctc/fill->color value) :key index :index index :title (tr "workspace.options.fill") diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs index 8dcccbc0c..7e614fa5d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs @@ -9,9 +9,9 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.main.data.helpers :as dsh] [app.main.data.workspace :as dw] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.features :as features] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input*]] @@ -56,7 +56,7 @@ wasm-renderer-enabled? (features/use-feature "render-wasm/v1") shapes (-> - (wsh/lookup-page-objects @st/state) + (dsh/lookup-page-objects @st/state) (select-keys ids) vals) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs index 1a4213a26..c4ef3a93d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs @@ -57,16 +57,16 @@ (or next (peek fonts))) current)) -(mf/defc font-item +(mf/defc font-item* {::mf/wrap [mf/memo]} - [{:keys [font current? on-click style]}] + [{:keys [font is-current on-click style]}] (let [item-ref (mf/use-ref) on-click (mf/use-fn (mf/deps font) #(on-click font))] (mf/use-effect - (mf/deps current?) + (mf/deps is-current) (fn [] - (when current? + (when is-current (let [element (mf/ref-val item-ref)] (when-not (dom/is-in-viewport? element) (dom/scroll-into-view! element)))))) @@ -76,9 +76,9 @@ :ref item-ref :on-click on-click} [:div {:class (stl/css-case :font-item true - :selected current?)} + :selected is-current)} [:span {:class (stl/css :label)} (:name font)] - [:span {:class (stl/css :icon)} (when current? i/tick)]]])) + [:span {:class (stl/css :icon)} (when is-current i/tick)]]])) (declare row-renderer) @@ -93,18 +93,23 @@ (comp (filter #(contains? backends (:backend %)))))] (into [] xform fonts))) -(mf/defc font-selector - [{:keys [on-select on-close current-font show-recent full-size] :as props}] - (let [selected (mf/use-state current-font) - state (mf/use-state {:term "" :backends #{}}) +(mf/defc font-selector* + [{:keys [on-select on-close current-font show-recent full-size]}] + (let [selected (mf/use-state current-font) + state* (mf/use-state + #(do {:term "" :backends #{}})) + state (deref state*) - flist (mf/use-ref) - input (mf/use-ref) + flist (mf/use-ref) + input (mf/use-ref) - fonts (mf/use-memo (mf/deps @state) #(filter-fonts @state @fonts/fonts)) - recent-fonts (mf/deref refs/workspace-recent-fonts) + fonts (mf/deref fonts/fonts) + fonts (mf/with-memo [state fonts] + (filter-fonts state fonts)) - full-size? (boolean (and full-size show-recent)) + recent-fonts (mf/deref refs/recent-fonts) + + full-size? (boolean (and full-size show-recent)) select-next (mf/use-fn @@ -136,7 +141,7 @@ on-filter-change (mf/use-fn (fn [event] - (swap! state assoc :term event))) + (swap! state* assoc :term event))) on-select-and-close (mf/use-fn @@ -145,9 +150,6 @@ (on-select font) (on-close)))] - (mf/with-effect [fonts] - (st/emit! (fts/load-recent-fonts fonts))) - (mf/with-effect [fonts] (let [key (events/listen js/document "keydown" on-key-down)] #(events/unlistenByKey key))) @@ -176,18 +178,18 @@ [:div {:class (stl/css-case :font-selector-dropdown true :font-selector-dropdown-full-size full-size?)} [:div {:class (stl/css :header)} [:& search-bar {:on-change on-filter-change - :value (:term @state) + :value (:term state) :auto-focus true :placeholder (tr "workspace.options.search-font")}] (when (and recent-fonts show-recent) [:section {:class (stl/css :show-recent)} [:p {:class (stl/css :title)} (tr "workspace.options.recent-fonts")] (for [[idx font] (d/enumerate recent-fonts)] - [:& font-item {:key (dm/str "font-" idx) - :font font - :style {} - :on-click on-select-and-close - :current? (= (:id font) (:id @selected))}])])] + [:> font-item* {:key (dm/str "font-" idx) + :font font + :style {} + :on-click on-select-and-close + :is-current (= (:id font) (:id @selected))}])])] [:div {:class (stl/css-case :fonts-list true :fonts-list-full-size full-size?)} @@ -211,11 +213,11 @@ style (unchecked-get props "style") font (nth fonts index)] (mf/html - [:& font-item {:key key - :font font - :style style - :on-click on-select - :current? (= (:id font) (:id selected))}]))) + [:> font-item* {:key key + :font font + :style style + :on-click on-select + :is-current (= (:id font) (:id selected))}]))) (mf/defc font-options {::mf/wrap-props false} @@ -228,14 +230,14 @@ fonts (mf/deref fonts/fontsdb) font (get fonts font-id) - recent-fonts (mf/deref refs/workspace-recent-fonts) + last-font (mf/use-ref nil) open-selector? (mf/use-state false) change-font (mf/use-fn - (mf/deps on-change fonts recent-fonts) + (mf/deps on-change fonts) (fn [new-font-id] (let [{:keys [family] :as font} (get fonts new-font-id) {:keys [id name weight style]} (fonts/get-default-variant font)] @@ -286,7 +288,7 @@ [:* (when @open-selector? - [:& font-selector + [:> font-selector* {:current-font font :on-close on-font-selector-close :on-select on-font-select @@ -448,7 +450,7 @@ (mf/defc typography-advanced-options {::mf/wrap [mf/memo]} - [{:keys [visible? typography editable? name-input-ref on-close on-change on-name-blur local? navigate-to-library on-key-down]}] + [{:keys [visible? typography editable? name-input-ref on-close on-change on-name-blur local? navigate-to-library on-key-down]}] (let [ref (mf/use-ref nil) font-data (fonts/get-font-data (:font-id typography))] (fonts/ensure-loaded! (:font-id typography)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs index aa3294438..c1ba935ed 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs @@ -20,7 +20,7 @@ [okulary.core :as l] [rumext.v2 :as mf])) -(def lens:background-color +(def ^:private ref:background-color (-> (l/key :background) (l/derived refs/workspace-page))) @@ -28,7 +28,7 @@ {::mf/wrap [mf/memo] ::mf/wrap-props false} [] - (let [background (mf/deref lens:background-color) + (let [background (mf/deref ref:background-color) on-change (mf/use-fn #(st/emit! (dw/change-canvas-color %))) on-open (mf/use-fn #(st/emit! (dwu/start-undo-transaction :options))) on-close (mf/use-fn #(st/emit! (dwu/commit-undo-transaction :options)))] diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs index 0486d9249..44a80bbbc 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs @@ -10,6 +10,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.main.data.common :as dcm] + [app.main.data.helpers :as dsh] [app.main.data.modal :as modal] [app.main.data.workspace :as dw] [app.main.refs :as refs] @@ -27,6 +28,29 @@ [okulary.core :as l] [rumext.v2 :as mf])) +;; FIXME: can we unify this two refs in one? + +(def ^:private ref:file-with-pages + "A derived state of the current file, without data with the + exception of list of pages" + (l/derived (fn [{:keys [data] :as file}] + (-> file + (dissoc :data) + (assoc :pages (:pages data)))) + refs/file + =)) + +(defn- make-page-ref + "Create a derived state that poins to a page identified by `page-id` + without including the page objects (mainly for avoid rerender on + each object change)" + [page-id] + (l/derived (fn [fdata] + (-> (dsh/get-page fdata page-id) + (dissoc :objects))) + refs/workspace-data + =)) + ;; --- Page Item (mf/defc page-item @@ -155,17 +179,11 @@ ;; --- Page Item Wrapper -(defn- make-page-ref - [page-id] - (l/derived (fn [state] - (let [page (get-in state [:workspace-data :pages-index page-id])] - (select-keys page [:id :name]))) - st/state =)) - (mf/defc page-item-wrapper {::mf/wrap-props false} [{:keys [page-id index deletable? selected? editing?]}] - (let [page-ref (mf/use-memo (mf/deps page-id) #(make-page-ref page-id)) + (let [page-ref (mf/with-memo [page-id] + (make-page-ref page-id)) page (mf/deref page-ref)] [:& page-item {:page page :index index @@ -198,7 +216,7 @@ (mf/defc sitemap {::mf/wrap-props false} [{:keys [size show-pages? toggle-pages]}] - (let [file (mf/deref refs/workspace-file) + (let [file (mf/deref ref:file-with-pages) file-id (get file :id) project-id (get file :project-id) @@ -207,6 +225,7 @@ (fn [event] (st/emit! (dw/create-page {:file-id file-id :project-id project-id})) (-> event dom/get-current-target dom/blur!))) + read-only? (mf/use-ctx ctx/workspace-read-only?) permissions (mf/use-ctx ctx/permissions)] diff --git a/frontend/src/app/main/ui/workspace/tokens/changes.cljs b/frontend/src/app/main/ui/workspace/tokens/changes.cljs index 6724f2541..2e458dd95 100644 --- a/frontend/src/app/main/ui/workspace/tokens/changes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/changes.cljs @@ -9,11 +9,11 @@ [app.common.types.shape.radius :as ctsr] [app.common.types.token :as ctt] [app.common.types.tokens-lib :as ctob] + [app.main.data.helpers :as dsh] [app.main.data.workspace :as udw] [app.main.data.workspace.colors :as wdc] [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.transforms :as dwt] [app.main.data.workspace.undo :as dwu] [app.main.store :as st] @@ -36,7 +36,8 @@ (ptk/reify ::apply-token ptk/WatchEvent (watch [_ state _] - (when-let [tokens (some-> (get-in state [:workspace-data :tokens-lib]) + (when-let [tokens (some-> (dsh/lookup-file-data state) + (get :tokens-lib) (ctob/get-active-themes-set-tokens))] (->> (rx/from (sd/resolve-tokens+ tokens)) (rx/mapcat @@ -179,7 +180,7 @@ (ptk/reify ::update-layout-spacing ptk/WatchEvent (watch [_ state _] - (let [layout-shape-ids (->> (wsh/lookup-shapes state shape-ids) + (let [layout-shape-ids (->> (dsh/lookup-shapes state shape-ids) (eduction (filter :layout) (map :id))) diff --git a/frontend/src/app/main/ui/workspace/tokens/token_set.cljs b/frontend/src/app/main/ui/workspace/tokens/token_set.cljs index 9a38202d8..22752a848 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_set.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_set.cljs @@ -1,17 +1,24 @@ (ns app.main.ui.workspace.tokens.token-set (:require - [app.common.types.tokens-lib :as ctob])) + [app.common.types.tokens-lib :as ctob] + [app.main.data.helpers :as dsh])) -(defn get-workspace-tokens-lib [state] - (get-in state [:workspace-data :tokens-lib])) +(defn get-workspace-tokens-lib + [state] + (-> (dsh/lookup-file-data state) + (get :tokens-lib))) ;; Themes ---------------------------------------------------------------------- -(defn get-active-theme-ids [state] - (get-in state [:workspace-data :token-active-themes] #{})) +(defn get-active-theme-ids + [state] + (-> (dsh/lookup-file-data state) + (get :token-active-themes #{}))) -(defn get-temp-theme-id [state] - (get-in state [:workspace-data :token-theme-temporary-id])) +(defn get-temp-theme-id + [state] + (-> (dsh/lookup-file-data state) + (get :token-theme-temporary-id))) (defn update-theme-id [state] @@ -22,8 +29,11 @@ (= 1 (count active-themes)) (first active-themes) :else temporary-theme-id))) -(defn get-workspace-token-theme [id state] - (get-in state [:workspace-data :token-themes-index id])) +(defn get-workspace-token-theme + [id state] + (-> (dsh/lookup-file-data state) + (get :token-themes-index) + (get id))) (defn add-token-set-to-token-theme [token-set-id token-theme] (update token-theme :sets conj token-set-id)) diff --git a/frontend/src/app/main/ui/workspace/tokens/update.cljs b/frontend/src/app/main/ui/workspace/tokens/update.cljs index ffe23f261..15a417cd2 100644 --- a/frontend/src/app/main/ui/workspace/tokens/update.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/update.cljs @@ -1,8 +1,8 @@ (ns app.main.ui.workspace.tokens.update (:require [app.common.types.token :as ctt] + [app.main.data.helpers :as dsh] [app.main.data.workspace.shape-layout :as dwsl] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.ui.workspace.tokens.changes :as wtch] [app.main.ui.workspace.tokens.style-dictionary :as wtsd] @@ -107,7 +107,7 @@ shapes-update-info)) (defn update-tokens [state resolved-tokens] - (->> (wsh/lookup-page-objects state) + (->> (dsh/lookup-page-objects state) (collect-shapes-update-info resolved-tokens) (actionize-shapes-update-info))) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 33f0cc925..2a31a1013 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -74,8 +74,8 @@ objects selected)) -(mf/defc viewport-classic - [{:keys [selected wglobal wlocal layout file palete-size] :as props}] +(mf/defc viewport-classic* + [{:keys [selected wglobal wlocal layout file page palete-size]}] (let [;; When adding data from workspace-local revisit `app.main.ui.workspace` to check ;; that the new parameter is sent {:keys [edit-path @@ -100,13 +100,12 @@ read-only? (mf/use-ctx ctx/workspace-read-only?) ;; DEREFS - drawing (mf/deref refs/workspace-drawing) focus (mf/deref refs/workspace-focus-selected) - page (mf/deref refs/workspace-page) - objects (get page :objects) + file-id (get file :id) page-id (get page :id) + objects (get page :objects) background (get page :background clr/canvas) base-objects (ui-hooks/with-focus-objects objects focus) @@ -158,7 +157,6 @@ drawing-tool (:tool drawing) drawing-obj (:object drawing) - selected-frames (into #{} (map :frame-id) selected-shapes) ;; Only when we have all the selected shapes in one frame @@ -302,12 +300,12 @@ :edition edition}])]]] (when show-comments? - [:& comments/comments-layer {:vbox vbox - :vport vport - :zoom zoom - :drawing drawing - :page-id page-id - :file-id (:id file)}]) + [:> comments/comments-layer* {:vbox vbox + :page-id page-id + :file-id file-id + :vport vport + :zoom zoom + :drawing drawing}]) (when picking-color? [:& pixel-overlay/pixel-overlay {:vport vport @@ -568,6 +566,7 @@ [:> guides/viewport-guides* {:zoom zoom :vbox vbox + :guides (:guides page) :hover-frame guide-frame :disabled-guides disabled-guides? :modifiers modifiers}]) @@ -648,6 +647,7 @@ :modifiers modifiers :shape frame :view-only true}]))] + [:g.scrollbar-wrapper {:clipPath "url(#clip-handlers)"} [:& scroll-bars/viewport-scrollbars {:objects base-objects @@ -655,9 +655,9 @@ :vbox vbox :bottom-padding (when palete-size (+ palete-size 8))}]]]]])) -(mf/defc viewport +(mf/defc viewport* [props] (let [wasm-renderer-enabled? (features/use-feature "render-wasm/v1")] (if ^boolean wasm-renderer-enabled? - [:& viewport.wasm/viewport props] - [:& viewport-classic props]))) + [:> viewport.wasm/viewport* props] + [:> viewport-classic* props]))) diff --git a/frontend/src/app/main/ui/workspace/viewport/comments.cljs b/frontend/src/app/main/ui/workspace/viewport/comments.cljs index 9efd425ba..764f5e87d 100644 --- a/frontend/src/app/main/ui/workspace/viewport/comments.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/comments.cljs @@ -9,6 +9,7 @@ (:require [app.common.data.macros :as dm] [app.main.data.comments :as dcm] + [app.main.data.helpers :as dsh] [app.main.data.workspace.comments :as dwcm] [app.main.refs :as refs] [app.main.store :as st] @@ -24,38 +25,43 @@ (assoc :frame-id (dm/get-in positions [id :frame-id]))) thread)) -(mf/defc comments-layer - {::mf/props :obj} - [{:keys [vbox vport zoom file-id page-id drawing] :as props}] - (let [vbox-x (dm/get-prop vbox :x) - vbox-y (dm/get-prop vbox :y) - vport-w (dm/get-prop vport :width) - vport-h (dm/get-prop vport :height) +(def ^:private ref:thread-positions + (l/derived (fn [state] + (-> (dsh/lookup-page state) + (get :comment-thread-positions))) + st/state)) - pos-x (* (- vbox-x) zoom) - pos-y (* (- vbox-y) zoom) +(mf/defc comments-layer* + [{:keys [vbox vport zoom drawing file-id page-id]}] + (let [vbox-x (dm/get-prop vbox :x) + vbox-y (dm/get-prop vbox :y) + vport-w (dm/get-prop vport :width) + vport-h (dm/get-prop vport :height) - profile (mf/deref refs/profile) - profiles (mf/deref refs/profiles) - local (mf/deref refs/comments-local) + pos-x (* (- vbox-x) zoom) + pos-y (* (- vbox-y) zoom) - positions-ref - (mf/with-memo [page-id] - ;; FIXME: use lookup helpers here - (-> (l/in [:workspace-data :pages-index page-id :comment-thread-positions]) - (l/derived st/state))) + profile (mf/deref refs/profile) + local (mf/deref refs/comments-local) - positions (mf/deref positions-ref) - threads-map (mf/deref refs/threads-ref) + positions (mf/deref ref:thread-positions) + + threads-map (mf/deref refs/threads) + threads-map (mf/with-memo [threads-map page-id positions] + (reduce-kv (fn [threads id thread] + (if (= (:page-id thread) page-id) + (assoc threads id (update-position positions thread)) + threads)) + {} + threads-map)) threads - (mf/with-memo [threads-map positions local profile] + (mf/with-memo [threads-map local profile] (->> (vals threads-map) - (filter #(= (:page-id %) page-id)) - (mapv (partial update-position positions)) (dcm/apply-filters local profile))) - viewport (assoc vport :offset-x pos-x :offset-y pos-y) + viewport + (assoc vport :offset-x pos-x :offset-y pos-y) on-draft-cancel (mf/use-fn #(st/emit! :interrupt)) @@ -78,7 +84,6 @@ :style {:transform (dm/fmt "translate(%px, %px)" pos-x pos-y)}} (for [item threads] [:> cmt/comment-floating-bubble* {:thread item - :profiles profiles :zoom zoom :is-open (= (:id item) (:open local)) :key (:seqn item)}]) @@ -86,15 +91,14 @@ (when-let [id (:open local)] (when-let [thread (get threads-map id)] (when (seq (dcm/apply-filters local profile [thread])) - [:> cmt/comment-floating-thread* {:thread (update-position positions thread) - :profiles profiles - :viewport viewport - :zoom zoom}]))) + [:> cmt/comment-floating-thread* + {:thread (update-position positions thread) + :viewport viewport + :zoom zoom}]))) (when-let [draft (:comment drawing)] - [:> cmt/comment-floating-thread-draft* {:draft draft - :profiles profiles - :on-cancel on-draft-cancel - :on-submit on-draft-submit - :zoom zoom}])]]])) - + [:> cmt/comment-floating-thread-draft* + {:draft draft + :on-cancel on-draft-cancel + :on-submit on-draft-submit + :zoom zoom}])]]])) diff --git a/frontend/src/app/main/ui/workspace/viewport/guides.cljs b/frontend/src/app/main/ui/workspace/viewport/guides.cljs index f6608a4a7..9d044ead5 100644 --- a/frontend/src/app/main/ui/workspace/viewport/guides.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/guides.cljs @@ -23,7 +23,6 @@ [app.main.ui.formats :as fmt] [app.main.ui.workspace.viewport.rulers :as rulers] [app.util.dom :as dom] - [okulary.core :as l] [rumext.v2 :as mf])) (def guide-width 1) @@ -448,18 +447,14 @@ :is-hover true :hover-frame frame}])])) -(def ^:private lens:workspace-guides - (-> (l/key :guides) - (l/derived refs/workspace-page))) - (mf/defc viewport-guides* {::mf/wrap [mf/memo] ::mf/props :obj} - [{:keys [zoom vbox hover-frame disabled-guides modifiers]}] - (let [guides (mf/deref lens:workspace-guides) - guides (mf/with-memo [guides vbox] - (->> (vals guides) - (filter (partial guide-inside-vbox? zoom vbox)))) + [{:keys [zoom vbox hover-frame disabled-guides modifiers guides]}] + (let [guides + (mf/with-memo [guides vbox] + (->> (vals guides) + (filter (partial guide-inside-vbox? zoom vbox)))) focus (mf/deref refs/workspace-focus-selected) diff --git a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs index be4cc88fa..5304facbb 100644 --- a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs +++ b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs @@ -74,8 +74,8 @@ objects selected)) -(mf/defc viewport - [{:keys [selected wglobal wlocal layout file palete-size] :as props}] +(mf/defc viewport* + [{:keys [selected wglobal wlocal layout file page palete-size]}] (let [;; When adding data from workspace-local revisit `app.main.ui.workspace` to check ;; that the new parameter is sent {:keys [edit-path @@ -102,7 +102,6 @@ drawing (mf/deref refs/workspace-drawing) focus (mf/deref refs/workspace-focus-selected) - page (mf/deref refs/workspace-page) objects (get page :objects) page-id (get page :id) background (get page :background clr/canvas) @@ -341,12 +340,11 @@ :edition edition}])]]] (when show-comments? - [:& comments/comments-layer {:vbox vbox - :vport vport - :zoom zoom - :drawing drawing - :page-id page-id - :file-id (:id file)}]) + [:> comments/comments-layer* {:vbox vbox + :page-id page-id + :vport vport + :zoom zoom + :drawing drawing}]) (when picking-color? [:& pixel-overlay/pixel-overlay {:vport vport @@ -571,6 +569,7 @@ [:> guides/viewport-guides* {:zoom zoom :vbox vbox + :guides (:guides page) :hover-frame guide-frame :disabled-guides disabled-guides? :modifiers modifiers}]) diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index 7b059d7c2..773869e43 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -8,7 +8,6 @@ "RPC for plugins runtime." (:require [app.common.data :as d] - [app.common.data.macros :as dm] [app.common.files.changes-builder :as cb] [app.common.files.helpers :as cfh] [app.common.geom.point :as gpt] @@ -19,6 +18,7 @@ [app.common.uuid :as uuid] [app.main.data.changes :as ch] [app.main.data.common :as dcm] + [app.main.data.helpers :as dsh] [app.main.data.workspace :as dw] [app.main.data.workspace.bool :as dwb] [app.main.data.workspace.colors :as dwc] @@ -48,15 +48,17 @@ ;; (defn create-shape [plugin-id type] - (let [page-id (:current-page-id @st/state) - page (dm/get-in @st/state [:workspace-data :pages-index page-id]) + (let [page (dsh/lookup-page @st/state) shape (cts/setup-shape {:type type - :x 0 :y 0 :width 100 :height 100}) + :x 0 :y 0 + :width 100 + :height 100}) changes (-> (cb/empty-changes) (cb/with-page page) (cb/with-objects (:objects page)) (cb/add-object shape))] + (st/emit! (ch/commit-changes changes)) (shape/shape-proxy plugin-id (:id shape)))) @@ -160,7 +162,7 @@ (map #(obj/get % "$id")) (mapcat #(cfh/get-children-with-self objects %))) file-id (:current-file-id @st/state) - shared-libs (:libraries @st/state)] + shared-libs (:files @st/state)] (->> (ctc/extract-all-colors shapes file-id shared-libs) (group-by :attrs) @@ -182,7 +184,7 @@ :else (let [file-id (:current-file-id @st/state) - shared-libs (:libraries @st/state) + shared-libs (:files @st/state) objects (u/locate-objects) shapes (->> shapes @@ -295,8 +297,7 @@ :createPath (fn [] - (let [page-id (:current-page-id @st/state) - page (dm/get-in @st/state [:workspace-data :pages-index page-id]) + (let [page (dsh/lookup-page @st/state) shape (cts/setup-shape {:type :path :content [{:command :move-to :params {:x 0 :y 0}} @@ -306,6 +307,7 @@ (cb/with-page page) (cb/with-objects (:objects page)) (cb/add-object shape))] + (st/emit! (ch/commit-changes changes)) (shape/shape-proxy plugin-id (:id shape)))) @@ -316,9 +318,7 @@ (u/display-not-valid :createText text) :else - (let [file-id (:current-file-id @st/state) - page-id (:current-page-id @st/state) - page (dm/get-in @st/state [:workspace-data :pages-index page-id]) + (let [page (dsh/lookup-page @st/state) shape (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width}) (txt/change-text text) (assoc :position-data nil)) @@ -327,8 +327,9 @@ (cb/with-page page) (cb/with-objects (:objects page)) (cb/add-object shape))] + (st/emit! (ch/commit-changes changes)) - (shape/shape-proxy plugin-id file-id page-id (:id shape))))) + (shape/shape-proxy plugin-id (:id shape))))) :createShapeFromSvg (fn [svg-string] diff --git a/frontend/src/app/plugins/comments.cljs b/frontend/src/app/plugins/comments.cljs index 623dc68a0..b7c41530c 100644 --- a/frontend/src/app/plugins/comments.cljs +++ b/frontend/src/app/plugins/comments.cljs @@ -9,6 +9,7 @@ [app.common.geom.point :as gpt] [app.common.spec :as us] [app.main.data.comments :as dc] + [app.main.data.helpers :as dsh] [app.main.data.workspace.comments :as dwc] [app.main.repo :as rp] [app.main.store :as st] @@ -25,7 +26,7 @@ (obj/type-of? p "CommentProxy")) (defn comment-proxy - [plugin-id file-id page-id thread-id users data] + [plugin-id file-id page-id thread-id data] (let [data* (atom data)] (obj/reify {:name "CommentProxy"} ;; Private properties @@ -36,9 +37,15 @@ :$id {:enumerable false :get (fn [] (:id data))} ;; Public properties + + ;; FIXME: inconsistent with comment-thread: owner :user - {:get - (fn [] (user/user-proxy plugin-id (get users (:owner-id data))))} + {:get #(->> (dc/get-owner data) + (user/user-proxy plugin-id))} + + :owner + {:get #(->> (dc/get-owner data) + (user/user-proxy plugin-id))} :date {:get @@ -86,20 +93,22 @@ (obj/type-of? p "CommentThreadProxy")) (defn comment-thread-proxy - [plugin-id file-id page-id users data] + [plugin-id file-id page-id data] (let [data* (atom data)] (obj/reify {:name "CommentThreadProxy"} :$plugin {:enumerable false :get (fn [] plugin-id)} :$file {:enumerable false :get (fn [] file-id)} :$page {:enumerable false :get (fn [] page-id)} :$id {:enumerable false :get (fn [] (:id data))} - :$users {:enumerable false :get (fn [] users)} :page {:enumerable false :get #(u/locate-page file-id page-id)} :seqNumber {:get #(:seqn data)} - :owner {:get #(user/user-proxy plugin-id (get users (:owner-id data)))} :board {:get #(shape/shape-proxy plugin-id file-id page-id (:frame-id data))} + :owner + {:get #(->> (dc/get-owner data) + (user/user-proxy plugin-id))} + :position {:get (fn [] @@ -152,7 +161,7 @@ (fn [comments] (resolve (format/format-array - #(comment-proxy plugin-id file-id page-id (:id data) users %) comments))) + #(comment-proxy plugin-id file-id page-id (:id data) %) comments))) reject)))))) :reply @@ -168,12 +177,12 @@ (js/Promise. (fn [resolve reject] (->> (rp/cmd! :create-comment {:thread-id (:id data) :content content}) - (rx/subs! #(resolve (comment-proxy plugin-id file-id page-id (:id data) users %)) reject)))))) + (rx/subs! #(resolve (comment-proxy plugin-id file-id page-id (:id data) %)) reject)))))) :remove (fn [] (let [profile (:profile @st/state) - owner (get users (:owner-id data))] + owner (dsh/lookup-profile @st/state (:owner-id data))] (cond (not (r/check-permission plugin-id "comment:write")) (u/display-not-valid :remove "Plugin doesn't have 'comment:write' permission") diff --git a/frontend/src/app/plugins/events.cljs b/frontend/src/app/plugins/events.cljs index 313f4c3b6..a4a12c5b1 100644 --- a/frontend/src/app/plugins/events.cljs +++ b/frontend/src/app/plugins/events.cljs @@ -7,7 +7,7 @@ (ns app.plugins.events (:require [app.common.data.macros :as dm] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [app.main.store :as st] [app.plugins.file :as file] [app.plugins.page :as page] @@ -63,8 +63,8 @@ (defmethod handle-state-change "shapechange" [_ plugin-id old-val new-val props] (if-let [shape-id (-> (obj/get props "shapeId") parser/parse-id)] - (let [old-shape (wsh/lookup-shape old-val shape-id) - new-shape (wsh/lookup-shape new-val shape-id) + (let [old-shape (dsh/lookup-shape old-val shape-id) + new-shape (dsh/lookup-shape new-val shape-id) file-id (:current-file-id new-val) page-id (:current-page-id new-val)] diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index 506fefdac..3f447325f 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -929,7 +929,7 @@ :connected {:get (fn [] - (let [libraries (get @st/state :libraries)] + (let [libraries (get @st/state :files)] (apply array (->> libraries keys (map (partial library-proxy plugin-id))))))} :availableLibraries @@ -937,7 +937,7 @@ (let [team-id (:current-team-id @st/state)] (js/Promise. (fn [resolve reject] - (let [current-libs (into #{} (map first) (get @st/state :libraries))] + (let [current-libs (into #{} (map first) (get @st/state :files))] (->> (rp/cmd! :get-team-shared-files {:team-id team-id}) (rx/map (fn [result] (->> result diff --git a/frontend/src/app/plugins/page.cljs b/frontend/src/app/plugins/page.cljs index e73cd5683..373a9b93c 100644 --- a/frontend/src/app/plugins/page.cljs +++ b/frontend/src/app/plugins/page.cljs @@ -369,11 +369,7 @@ :content content} (fn [data] - (->> (rp/cmd! :get-team-users {:file-id file-id}) - (rx/subs! - (fn [users] - (let [users (d/index-by :id users)] - (resolve (pc/comment-thread-proxy plugin-id file-id id users data))))))) + (resolve (pc/comment-thread-proxy plugin-id file-id id data))) false)))))))) :removeCommentThread @@ -396,7 +392,7 @@ (fn [criteria] (let [only-yours (boolean (obj/get criteria "onlyYours" false)) show-resolved (boolean (obj/get criteria "showResolved" true)) - user-id (-> @st/state :profile :id)] + user-id (:profile-id @st/state)] (js/Promise. (fn [resolve reject] (cond @@ -406,14 +402,11 @@ (reject "Plugin doesn't have 'comment:read' permission")) :else - (->> (rx/zip (rp/cmd! :get-team-users {:file-id file-id}) - (rp/cmd! :get-comment-threads {:file-id file-id})) - (rx/take 1) + (->> (rp/cmd! :get-comment-threads {:file-id file-id}) (rx/subs! - (fn [[users comments]] - (let [users (d/index-by :id users) - comments - (cond->> comments + (fn [threads] + (let [threads + (cond->> threads (not show-resolved) (filter (comp not :is-resolved)) @@ -421,5 +414,5 @@ (filter #(contains? (:participants %) user-id)))] (resolve (format/format-array - #(pc/comment-thread-proxy plugin-id file-id id users %) comments)))) + #(pc/comment-thread-proxy plugin-id file-id id %) threads)))) reject))))))))) diff --git a/frontend/src/app/plugins/utils.cljs b/frontend/src/app/plugins/utils.cljs index 51d5216f7..494d3f212 100644 --- a/frontend/src/app/plugins/utils.cljs +++ b/frontend/src/app/plugins/utils.cljs @@ -11,21 +11,20 @@ [app.common.data.macros :as dm] [app.common.types.container :as ctn] [app.common.types.file :as ctf] + [app.main.data.helpers :as dsh] [app.main.store :as st] [app.util.object :as obj])) (defn locate-file [id] (assert (uuid? id) "File not valid uuid") - (if (= id (:current-file-id @st/state)) - (-> (:workspace-file @st/state) - (assoc :data (:workspace-data @st/state))) - (dm/get-in @st/state [:libraries id]))) + (dsh/lookup-file @st/state id)) (defn locate-page [file-id id] (assert (uuid? id) "Page not valid uuid") - (dm/get-in (locate-file file-id) [:data :pages-index id])) + (-> (dsh/lookup-file-data @st/state file-id) + (dsh/get-page id))) (defn locate-objects ([] @@ -62,13 +61,15 @@ (let [{:keys [profile-id]} (locate-presence session-id)] (dm/get-in @st/state [:users profile-id]))) +;; FIXME: the impl looks strange: objects is passed by parameters but +;; then the rest of the file is looked up directly from state.... (?) (defn locate-component [objects shape] - (let [current-file-id (:current-file-id @st/state) - workspace-data (:workspace-data @st/state) - libraries (:libraries @st/state) + (let [state (deref st/state) + file (dsh/lookup-file state) + libraries (dsh/lookup-libraries state) root (ctn/get-instance-root objects shape)] - [root (ctf/resolve-component root {:id current-file-id :data workspace-data} libraries {:include-deleted? true})])) + [root (ctf/resolve-component root file libraries {:include-deleted? true})])) (defn proxy->file [proxy] @@ -87,7 +88,7 @@ [proxy] (let [file-id (obj/get proxy "$file") page-id (obj/get proxy "$page") - id (obj/get proxy "$id")] + id (obj/get proxy "$id")] (when (and (some? file-id) (some? page-id) (some? id)) (locate-shape file-id page-id id)))) @@ -167,9 +168,12 @@ (defn get-state ([self attr] - (let [id (get-data self :id) - page-id (d/nilv (get-data self :page-id) (:current-page-id @st/state))] - (dm/get-in @st/state [:workspace-data :pages-index page-id :objects id attr]))) + (let [id (get-data self :id) + page-id (or (get-data self :page-id) + (:current-page-id @st/state))] + (-> (dsh/lookup-page-objects @st/state page-id) + (dm/get-in [:objects id attr])))) + ([self attr mapfn] (-> (get-state self attr) (mapfn)))) diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index d4bea0de7..f48777c17 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -18,6 +18,7 @@ [app.main.data.changes :as dwc] [app.main.data.common :as dcm] [app.main.data.dashboard.shortcuts] + [app.main.data.helpers :as dsh] [app.main.data.preview :as dp] [app.main.data.viewer.shortcuts] [app.main.data.workspace :as dw] @@ -149,8 +150,10 @@ nil) (defn ^:export dump-data [] - (logjs "workspace-data" (get @st/state :workspace-data)) - nil) + (let [fdata (-> (dsh/lookup-file @st/state) + (get :data))] + (logjs "file-data" fdata) + nil)) (defn ^:export dump-buffer [] (logjs "last-events" @st/last-events) @@ -165,8 +168,7 @@ (defn dump-objects' [state] - (let [page-id (get state :current-page-id) - objects (get-in state [:workspace-data :pages-index page-id :objects])] + (let [objects (dsh/lookup-page-objects state)] (logjs "objects" objects) nil)) @@ -174,33 +176,25 @@ [] (dump-objects' @st/state)) -(defn dump-object' +(defn get-object [state name] - (let [page-id (get state :current-page-id) - objects (get-in state [:workspace-data :pages-index page-id :objects]) + (let [objects (dsh/lookup-page-objects state) result (or (d/seek (fn [shape] (= name (:name shape))) (vals objects)) (get objects (uuid/uuid name)))] - #_(logjs name result) - result - - #_nil)) + result)) (defn ^:export dump-object [name] - (dump-object' @st/state name)) + (get-object @st/state name)) -(defn dump-selected' +(defn get-selected [state] - (let [page-id (get state :current-page-id) - objects (get-in state [:workspace-data :pages-index page-id :objects]) - selected (get-in state [:workspace-local :selected]) - result (->> selected (map (d/getf objects)))] - (logjs "selected" result) - nil)) + (dsh/lookup-selected state)) (defn ^:export dump-selected [] - (dump-selected' @st/state)) + (logjs "selected" (get-selected @st/state)) + nil) (defn ^:export preview-selected [] @@ -208,26 +202,20 @@ (defn ^:export parent [] - (let [state @st/state - page-id (get state :current-page-id) - objects (get-in state [:workspace-data :pages-index page-id :objects]) - selected (first (get-in state [:workspace-local :selected])) - parent-id (get-in objects [selected :parent-id]) - parent (get objects parent-id)] - (when parent - (prn (str (:name parent) " - " (:id parent)))) + (let [objects (dsh/lookup-page-objects @st/state) + selected-id (first (dsh/get-selected-ids @st/state)) + parent-id (dm/get-in objects [selected-id :parent-id])] + (when-let [parent (get objects parent-id)] + (js/console.log (str (:name parent) " - " (:id parent)))) nil)) (defn ^:export frame [] - (let [state @st/state - page-id (get state :current-page-id) - objects (get-in state [:workspace-data :pages-index page-id :objects]) - selected (first (get-in state [:workspace-local :selected])) - frame-id (get-in objects [selected :frame-id]) - frame (get objects frame-id)] - (when frame - (prn (str (:name frame) " - " (:id frame)))) + (let [objects (dsh/lookup-page-objects @st/state) + selected-id (first (dsh/get-selected-ids @st/state)) + frame-id (dm/get-in objects [selected-id :frame-id])] + (when-let [frame (get objects frame-id)] + (js/console.log (str (:name frame) " - " (:id frame)))) nil)) (defn ^:export select-by-object-id @@ -246,9 +234,8 @@ ([state show-ids show-touched] (dump-tree' state show-ids show-touched false)) ([state show-ids show-touched show-modified] (let [page-id (get state :current-page-id) - file (assoc (get state :workspace-file) - :data (get state :workspace-data)) - libraries (get state :libraries)] + file (dsh/lookup-file state) + libraries (get state :files)] (ctf/dump-tree file page-id libraries {:show-ids show-ids :show-touched show-touched :show-modified show-modified})))) @@ -264,14 +251,11 @@ ([state shape-id show-ids show-touched] (dump-subtree' state shape-id show-ids show-touched false)) ([state shape-id show-ids show-touched show-modified] (let [page-id (get state :current-page-id) - file (assoc (get state :workspace-file) - :data (get state :workspace-data)) - libraries (get state :libraries) + file (dsh/lookup-file state) + libraries (get state :files) shape-id (if (some? shape-id) (uuid/uuid shape-id) - (let [objects (get-in state [:workspace-data :pages-index page-id :objects]) - selected (get-in state [:workspace-local :selected])] - (->> selected (map (d/getf objects)) first :id)))] + (first (dsh/lookup-selected state)))] (if (some? shape-id) (ctf/dump-subtree file page-id shape-id libraries {:show-ids show-ids :show-touched show-touched @@ -363,10 +347,10 @@ (defn ^:export dump-modifiers [] - (let [page-id (get @st/state :current-page-id) - objects (get-in @st/state [:workspace-data :pages-index page-id :objects])] - (.log js/console (modif->js (:workspace-modifiers @st/state) objects))) - nil) + (let [objects (dsh/lookup-page-objects @st/state) + modifiers (:workspace-modifiers @st/state)] + (js/console.log (modif->js modifiers objects)) + nil)) (defn ^:export set-workspace-read-only [read-only?] @@ -381,10 +365,8 @@ (defn ^:export validate ([] (validate nil)) ([shape-id] - (let [file (assoc (get @st/state :workspace-file) - :data (get @st/state :workspace-data)) - libraries (get @st/state :libraries)] - + (let [file (dsh/lookup-file @st/state) + libraries (get @st/state :files)] (try (->> (if-let [shape-id (some-> shape-id parse-uuid)] (let [page (dm/get-in file [:data :pages-index (get @st/state :current-page-id)])] @@ -398,9 +380,8 @@ (defn ^:export validate-schema [] (try - (-> (get @st/state :workspace-file) - (assoc :data (get @st/state :workspace-data)) - (cfv/validate-file-schema!)) + (let [file (dsh/lookup-file @st/state)] + (cfv/validate-file-schema! file)) (catch :default cause (errors/print-error! cause)))) @@ -413,11 +394,8 @@ (let [features (features/get-team-enabled-features state) sid (:session-id state) - file (get state :workspace-file) - fdata (get state :workspace-data) - - file (assoc file :data fdata) - libs (get state :libraries) + file (dsh/lookup-file state) + libs (get state :files) errors (cfv/validate-file file libs) _ (l/dbg :hint "repair current file" :errors (count errors)) diff --git a/frontend/test/frontend_tests/basic_shapes_test.cljs b/frontend/test/frontend_tests/basic_shapes_test.cljs index 6b7d9e912..adeb2e758 100644 --- a/frontend/test/frontend_tests/basic_shapes_test.cljs +++ b/frontend/test/frontend_tests/basic_shapes_test.cljs @@ -9,6 +9,7 @@ [app.common.test-helpers.files :as cthf] [app.common.test-helpers.ids-map :as cthi] [app.common.test-helpers.shapes :as cths] + [app.main.data.helpers :as dsh] [app.main.data.workspace.colors :as dc] [app.main.data.workspace.shapes :as dwsh] [cljs.test :as t :include-macros true] @@ -34,13 +35,10 @@ store done events (fn [new-state] (let [;; ==== Get - shape1' (get-in new-state [:workspace-data - :pages-index - (cthi/id :page1) - :objects - (cthi/id :shape1)]) - fills' (:fills shape1') - fill' (first fills')] + objects (dsh/lookup-page-objects new-state) + shape1' (get objects (cthi/id :shape1)) + fills' (:fills shape1') + fill' (first fills')] ;; ==== Check (t/is (some? shape1')) @@ -68,15 +66,11 @@ store done events (fn [new-state] (let [;; ==== Get - shape1' (get-in new-state [:workspace-data - :pages-index - (cthi/id :page1) - :objects - (cthi/id :shape1)]) - stroke' (-> (:strokes shape1') - first)] + objects (dsh/lookup-page-objects new-state) + shape1' (get objects (cthi/id :shape1)) + stroke' (first (:strokes shape1'))] - ;; ==== Check + ;; ==== Check ;; (println stroke') (t/is (some? shape1')) (t/is (= (:stroke-alignment stroke') :inner)) diff --git a/frontend/test/frontend_tests/helpers/libraries.cljs b/frontend/test/frontend_tests/helpers/libraries.cljs index 1d9137f56..ce1796f24 100644 --- a/frontend/test/frontend_tests/helpers/libraries.cljs +++ b/frontend/test/frontend_tests/helpers/libraries.cljs @@ -9,7 +9,7 @@ [app.common.files.helpers :as cfh] [app.common.types.container :as ctn] [app.common.types.file :as ctf] - [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.helpers :as dsh] [cljs.test :as t :include-macros true] [frontend-tests.helpers.pages :as thp])) @@ -111,7 +111,7 @@ root-inst (ctn/get-shape page root-inst-id) main-instance? (:main-instance root-inst) - libs (wsh/get-libraries state) + libs (dsh/lookup-libraries state) component (ctf/get-component libs (:component-file root-inst) (:component-id root-inst)) library (ctf/get-component-library libs root-inst) @@ -151,7 +151,7 @@ (let [page (thp/current-page state) root-inst (ctn/get-shape page root-inst-id) - libs (wsh/get-libraries state) + libs (dsh/lookup-libraries state) component (ctf/get-component libs (:component-file root-inst) (:component-id root-inst)) library (ctf/get-component-library libs root-inst) @@ -166,7 +166,7 @@ (defn resolve-component "Get the component with the given id and all its shapes." [state component-file component-id] - (let [libs (wsh/get-libraries state) + (let [libs (dsh/lookup-libraries state) component (ctf/get-component libs component-file component-id) library (ctf/get-component-library libs component) shapes-main (ctf/get-component-shapes (:data library) component)] diff --git a/frontend/test/frontend_tests/helpers/pages.cljs b/frontend/test/frontend_tests/helpers/pages.cljs index 69e617004..7a4e2e020 100644 --- a/frontend/test/frontend_tests/helpers/pages.cljs +++ b/frontend/test/frontend_tests/helpers/pages.cljs @@ -20,9 +20,9 @@ [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] + [app.main.data.helpers :as dsh] [app.main.data.workspace.groups :as dwg] - [app.main.data.workspace.layout :as layout] - [app.main.data.workspace.state-helpers :as wsh])) + [app.main.data.workspace.layout :as layout])) ;; ---- Helpers to manage pages and objects @@ -33,12 +33,15 @@ :current-page-id nil :workspace-layout layout/default-layout :workspace-global layout/default-global - :workspace-data {:id current-file-id - :options {:components-v2 true} - :components {} - :pages [] - :pages-index {}} - :workspace-libraries {} + + :files + {current-file-id + {:id current-file-id + :data {:id current-file-id + :options {:components-v2 true} + :components {} + :pages [] + :pages-index {}}}} :features-team #{"components/v2"}}) (def ^:private idmap (atom {})) @@ -48,8 +51,9 @@ (defn current-page [state] - (let [page-id (:current-page-id state)] - (get-in state [:workspace-data :pages-index page-id]))) + (let [page-id (:current-page-id state) + file-id (:current-file-id state)] + (get-in state [:files file-id :data :pages-index page-id]))) (defn id [label] @@ -65,20 +69,22 @@ (let [page (current-page state)] (cfh/get-children (:objects page) (id label)))) +(defn apply-changes + [state changes] + (let [file-id (:current-file-id state)] + (update-in state [:files file-id :data] cp/process-changes changes))) + (defn sample-page ([state] (sample-page state {})) ([state {:keys [id name] :as props :or {id (uuid/next) name "page1"}}] - (swap! idmap assoc :page id) (-> state (assoc :current-page-id id) - (update :workspace-data - cp/process-changes - [{:type :add-page - :id id - :name name}])))) + (apply-changes [{:type :add-page + :id id + :name name}])))) (defn sample-shape ([state label type] (sample-shape state type {})) @@ -87,13 +93,12 @@ frame (cfh/get-frame (:objects page)) shape (cts/setup-shape (merge {:type type :x 0 :y 0 :width 1 :height 1} props))] (swap! idmap assoc label (:id shape)) - (update state :workspace-data - cp/process-changes - [{:type :add-obj - :id (:id shape) - :page-id (:id page) - :frame-id (:id frame) - :obj shape}])))) + (apply-changes state + [{:type :add-obj + :id (:id shape) + :page-id (:id page) + :frame-id (:id frame) + :obj shape}])))) (defn group-shapes ([state label ids] (group-shapes state label ids "Group")) @@ -106,8 +111,7 @@ (dwg/prepare-create-group (pcb/empty-changes) nil (:objects page) (:id page) shapes prefix true)] (swap! idmap assoc label (:id group)) - (update state :workspace-data - cp/process-changes (:redo-changes changes))))))) + (apply-changes state (:redo-changes changes))))))) (defn frame-shapes ([state label ids] (frame-shapes state label ids "Board")) @@ -128,13 +132,12 @@ true)] (swap! idmap assoc label (:id frame)) - (update state :workspace-data - cp/process-changes (:redo-changes changes))))))) + (apply-changes state (:redo-changes changes))))))) (defn make-component [state instance-label component-label shape-ids] (let [page (current-page state) - objects (wsh/lookup-page-objects state (:id page)) + objects (dsh/lookup-page-objects state (:id page)) shapes (dwg/shapes-for-grouping objects shape-ids) [group component-id changes] @@ -149,15 +152,14 @@ (swap! idmap assoc instance-label (:id group) component-label component-id) - (update state :workspace-data - cp/process-changes (:redo-changes changes)))) + (apply-changes state (:redo-changes changes)))) (defn instantiate-component ([state label component-id] (instantiate-component state label component-id current-file-id)) ([state label component-id file-id] (let [page (current-page state) - libraries (wsh/get-libraries state) + libraries (dsh/lookup-libraries state) objects (:objects page) changes (-> (pcb/empty-changes nil (:id page)) @@ -173,26 +175,27 @@ libraries)] (swap! idmap assoc label (:id new-shape)) - (update state :workspace-data - cp/process-changes (:redo-changes changes))))) + (apply-changes state (:redo-changes changes))))) (defn move-to-library [state label name] (let [library-id (uuid/next) - data (get state :workspace-data)] + file-id (:current-file-id state) + data (get-in state [:files file-id :data])] (swap! idmap assoc label library-id) (-> state - (update :workspace-libraries - assoc library-id {:id library-id - :name name - :data {:id library-id - :options (:options data) - :pages (:pages data) - :pages-index (:pages-index data) - :components (:components data)}}) - (update :workspace-data - assoc :components {} :pages [] :pages-index {})))) - + (update :files assoc library-id + {:id library-id + :name name + :data {:id library-id + :options (:options data) + :pages (:pages data) + :pages-index (:pages-index data) + :components (:components data)}}) + (update-in [:files file-id :data] assoc + :components {} + :pages [] + :pages-index {})))) (defn simulate-copy-shape [selected objects libraries page file features version] diff --git a/frontend/test/frontend_tests/helpers/state.cljs b/frontend/test/frontend_tests/helpers/state.cljs index 4027ccf29..9a4f4b7f2 100644 --- a/frontend/test/frontend_tests/helpers/state.cljs +++ b/frontend/test/frontend_tests/helpers/state.cljs @@ -18,8 +18,6 @@ :workspace-global layout/default-global :current-file-id nil :current-page-id nil - :workspace-data nil - :workspace-libraries {} :features-team #{"components/v2"}}) (defn- on-error @@ -34,8 +32,7 @@ (assoc :current-file-id (:id file) :current-page-id (cthf/current-page-id file) :permissions {:can-edit true} - :workspace-file (dissoc file :data) - :workspace-data (:data file))) + :files {(:id file) file})) store (ptk/store {:state state :on-error on-error})] store)) @@ -64,7 +61,7 @@ (ptk/emit! store :the/end)))) -(defn get-file-from-store - [store] - (-> (:workspace-file store) - (assoc :data (:workspace-data store)))) +(defn get-file-from-state + [state] + (let [file-id (:current-file-id state)] + (get-in state [:files file-id]))) diff --git a/frontend/test/frontend_tests/logic/comp_remove_swap_slots_test.cljs b/frontend/test/frontend_tests/logic/comp_remove_swap_slots_test.cljs index f97bd7b08..feaf11c09 100644 --- a/frontend/test/frontend_tests/logic/comp_remove_swap_slots_test.cljs +++ b/frontend/test/frontend_tests/logic/comp_remove_swap_slots_test.cljs @@ -116,7 +116,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') blue1' (cths/get-shape file' :blue1) copied-blue1' (find-copied-shape blue1' page' uuid/zero)] @@ -155,7 +155,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b1' (cths/get-shape file' :frame-b1) blue1' (cths/get-shape file' :blue1) @@ -193,7 +193,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') yellow' (cths/get-shape file' :frame-yellow) blue1' (cths/get-shape file' :blue1) @@ -232,7 +232,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b2' (cths/get-shape file' :frame-b2) blue1' (cths/get-shape file' :blue1) @@ -272,7 +272,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') copied-blue1' (find-copied-shape blue1 page' uuid/zero)] @@ -309,7 +309,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') yellow' (cths/get-shape file' :frame-yellow) copied-blue1' (find-copied-shape blue1 page' (:id yellow'))] @@ -346,7 +346,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b2' (cths/get-shape file' :frame-b2) copied-blue1' (find-copied-shape blue1 page' (:id b2'))] @@ -380,7 +380,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') copied-yellow' (find-copied-shape yellow page' uuid/zero) blue1' (cths/get-shape file' :blue1) @@ -419,7 +419,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b1' (cths/get-shape file' :frame-b1) copied-yellow' (find-copied-shape yellow page' (:id b1')) @@ -459,7 +459,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b2' (cths/get-shape file' :frame-b2) copied-yellow' (find-copied-shape yellow page' (:id b2')) @@ -500,7 +500,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') copied-yellow' (find-copied-shape yellow page' uuid/zero) copied-blue1' (find-copied-shape blue1 page' (:id copied-yellow'))] @@ -537,7 +537,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b1' (cths/get-shape file' :frame-b1) copied-yellow' (find-copied-shape yellow page' (:id b1')) @@ -575,7 +575,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b2' (cths/get-shape file' :frame-b2) copied-yellow' (find-copied-shape yellow page' (:id b2')) @@ -609,7 +609,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') blue2' (cths/get-shape file' :blue-copy-in-green-copy) copied-green' (find-copied-shape green page' uuid/zero) @@ -648,7 +648,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b1' (cths/get-shape file' :frame-b1) blue2' (cths/get-shape file' :blue-copy-in-green-copy) @@ -688,7 +688,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b2' (cths/get-shape file' :frame-b2) blue2' (cths/get-shape file' :blue-copy-in-green-copy) @@ -731,7 +731,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') copied-green' (find-copied-shape green page' uuid/zero) copied-blue1' (find-copied-shape blue2 page' (:id copied-green'))] @@ -768,7 +768,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b1' (cths/get-shape file' :frame-b1) copied-green' (find-copied-shape green page' (:id b1')) @@ -806,7 +806,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') b2' (cths/get-shape file' :frame-b2) copied-green' (find-copied-shape green page' (:id b2')) @@ -855,7 +855,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') green' (cths/get-shape file' :frame-green) blue1' (cths/get-shape file' :blue1) diff --git a/frontend/test/frontend_tests/logic/components_and_tokens.cljs b/frontend/test/frontend_tests/logic/components_and_tokens.cljs index d561a75e7..1d8cf116d 100644 --- a/frontend/test/frontend_tests/logic/components_and_tokens.cljs +++ b/frontend/test/frontend_tests/logic/components_and_tokens.cljs @@ -14,10 +14,10 @@ [app.common.test-helpers.shapes :as cths] [app.common.test-helpers.tokens :as ctht] [app.common.types.tokens-lib :as ctob] + [app.main.data.helpers :as dsh] [app.main.data.tokens :as dt] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.selection :as dws] - [app.main.data.workspace.state-helpers :as wsh] [app.main.ui.workspace.tokens.changes :as wtch] [app.main.ui.workspace.tokens.update :as wtu] [cljs.test :as t :include-macros true] @@ -79,7 +79,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) frame1' (cths/get-shape file' :frame1) tokens-frame1' (:applied-tokens frame1')] @@ -111,8 +111,8 @@ store done events (fn [new-state] (let [;; ==== Get - selected (wsh/lookup-selected new-state) - c-frame1' (wsh/lookup-shape new-state (first selected)) + selected (dsh/lookup-selected new-state) + c-frame1' (dsh/lookup-shape new-state (first selected)) tokens-frame1' (:applied-tokens c-frame1')] ;; ==== Check @@ -145,7 +145,7 @@ store done events2 (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) c-frame1' (cths/get-shape file' :c-frame1) tokens-frame1' (:applied-tokens c-frame1')] @@ -181,7 +181,7 @@ store done events2 (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) c-frame1' (cths/get-shape file' :c-frame1) tokens-frame1' (:applied-tokens c-frame1')] @@ -215,7 +215,7 @@ store done events2 (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) c-frame1' (cths/get-shape file' :c-frame1) tokens-frame1' (:applied-tokens c-frame1')] @@ -256,7 +256,7 @@ store done events2 (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) c-frame1' (cths/get-shape file' :c-frame1) tokens-frame1' (:applied-tokens c-frame1')] @@ -296,7 +296,7 @@ store done events2 (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) c-frame1' (cths/get-shape file' :c-frame1) tokens-frame1' (:applied-tokens c-frame1')] @@ -390,7 +390,7 @@ store done events2 (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) frame1' (cths/get-shape file' :frame1) c-frame1' (cths/get-shape file' :c-frame1) tokens-frame1' (:applied-tokens c-frame1')] @@ -423,4 +423,4 @@ (t/is (empty? (:touched c-frame1'))))))))] (tohs/run-store-async - store step2 events identity)))) \ No newline at end of file + store step2 events identity)))) diff --git a/frontend/test/frontend_tests/logic/copying_and_duplicating_test.cljs b/frontend/test/frontend_tests/logic/copying_and_duplicating_test.cljs index 7cf889849..3d331c616 100644 --- a/frontend/test/frontend_tests/logic/copying_and_duplicating_test.cljs +++ b/frontend/test/frontend_tests/logic/copying_and_duplicating_test.cljs @@ -126,31 +126,32 @@ (not (:component-root %)))) (map :id))] (concat - (apply concat (mapv #(copy-paste-shape % file :target-page-label target-page-label :target-container-id uuid/zero) frame-1-instance-ids)) - (apply concat (mapv #(copy-paste-shape % file :target-page-label target-page-label :target-container-id uuid/zero) frame-1-instance-ids))))) + (apply concat + (mapv #(copy-paste-shape % file :target-page-label target-page-label :target-container-id uuid/zero) frame-1-instance-ids)) + (apply concat + (mapv #(copy-paste-shape % file :target-page-label target-page-label :target-container-id uuid/zero) frame-1-instance-ids))))) (t/deftest main-and-first-level-copy-1 - (t/async - done + (t/async done (with-redefs [uuid/next cthi/next-uuid] (let [;; ==== Setup file (setup-file) store (ths/setup-store file) - ;; ==== Action + ;; ==== Action - ;; For each main and first level copy: - ;; - Duplicate it two times with copy-paste. + ;; For each main and first level copy: + ;; - Duplicate it two times with copy-paste. events (concat (duplicate-each-main-and-first-level-copy file) - ;; - Change color of Simple1 + ;; - Change color of Simple1 (set-color-bottom-shape :frame-simple-1 file {:color "#111111"}))] (ths/run-store store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state)] + (let [file' (ths/get-file-from-state new-state)] (t/is (= (count-shapes file' "rect-simple-1" "#111111") 18))))))))) (t/deftest main-and-first-level-copy-2 @@ -176,7 +177,7 @@ (ths/run-store store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state)] + (let [file' (ths/get-file-from-state new-state)] (t/is (= (count-shapes file' "rect-simple-1" "#222222") 15))))))))) (t/deftest main-and-first-level-copy-3 @@ -203,7 +204,7 @@ (ths/run-store store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state)] + (let [file' (ths/get-file-from-state new-state)] (t/is (= (count-shapes file' "rect-simple-1" "#333333") 12))))))))) @@ -232,7 +233,7 @@ (ths/run-store store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state)] + (let [file' (ths/get-file-from-state new-state)] (t/is (= (count-shapes file' "rect-simple-1" "#444444") 6))))))))) (t/deftest copy-nested-in-main-1 @@ -255,7 +256,7 @@ (ths/run-store store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state)] + (let [file' (ths/get-file-from-state new-state)] ;; Check propagation to all copies. (t/is (= (count-shapes file' "rect-simple-1" "#111111") 28))))))))) @@ -279,7 +280,7 @@ (ths/run-store store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state)] + (let [file' (ths/get-file-from-state new-state)] ;; Check propagation to duplicated. (t/is (= (count-shapes file' "rect-simple-1" "#222222") 9))))))))) @@ -303,7 +304,7 @@ (ths/run-store store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state)] + (let [file' (ths/get-file-from-state new-state)] ;; Check that it's NOT PROPAGATED. (t/is (= (count-shapes file' "rect-simple-1" "#333333") 2))))))))) @@ -328,7 +329,7 @@ (ths/run-store store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state)] + (let [file' (ths/get-file-from-state new-state)] ;; Check propagation to all copies. (t/is (= (count-shapes file' "rect-simple-1" "#111111") 20))))))))) @@ -357,7 +358,7 @@ (ths/run-store store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state)] + (let [file' (ths/get-file-from-state new-state)] ;; Check that it's NOT PROPAGATED. (t/is (= (count-shapes file' "rect-simple-1" "#111111") 11)) (t/is (= (count-shapes file' "rect-simple-1" "#222222") 7)) @@ -365,8 +366,7 @@ (t/deftest copy-nested-3 - (t/async - done + (t/async done (with-redefs [uuid/next cthi/next-uuid] (let [;; ==== Setup file (setup-file) @@ -388,9 +388,9 @@ (ths/run-store store done events (fn [new-state] - (let [file' (-> (ths/get-file-from-store new-state) + (let [file' (-> (ths/get-file-from-state new-state) (cthf/switch-to-page :page-2))] ;; Check that it's NOT PROPAGATED. (t/is (= (count-shapes file' "rect-simple-1" "#111111") 10)) (t/is (= (count-shapes file' "rect-simple-1" "#222222") 4)) - (t/is (= (count-shapes file' "rect-simple-1" "#333333") 0))))))))) \ No newline at end of file + (t/is (= (count-shapes file' "rect-simple-1" "#333333") 0))))))))) diff --git a/frontend/test/frontend_tests/logic/frame_guides_test.cljs b/frontend/test/frontend_tests/logic/frame_guides_test.cljs index 721220fcd..c88f362ed 100644 --- a/frontend/test/frontend_tests/logic/frame_guides_test.cljs +++ b/frontend/test/frontend_tests/logic/frame_guides_test.cljs @@ -42,7 +42,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') guide' (-> page' diff --git a/frontend/test/frontend_tests/logic/groups_test.cljs b/frontend/test/frontend_tests/logic/groups_test.cljs index a535a586f..f123e47bf 100644 --- a/frontend/test/frontend_tests/logic/groups_test.cljs +++ b/frontend/test/frontend_tests/logic/groups_test.cljs @@ -39,7 +39,7 @@ store done events (fn [new-state] (let [;; ==== Get - file' (ths/get-file-from-store new-state) + file' (ths/get-file-from-state new-state) page' (cthf/current-page file') group-id (->> (:objects page') vals diff --git a/frontend/test/frontend_tests/plugins/context_shapes_test.cljs b/frontend/test/frontend_tests/plugins/context_shapes_test.cljs index f73ba9669..4fb747780 100644 --- a/frontend/test/frontend_tests/plugins/context_shapes_test.cljs +++ b/frontend/test/frontend_tests/plugins/context_shapes_test.cljs @@ -18,17 +18,20 @@ (t/deftest test-common-shape-properties (let [;; ==== Setup - store - (ths/setup-store (cthf/sample-file :file1 :page-label :page1)) - - _ (set! st/state store) + store (ths/setup-store + (cthf/sample-file :file1 :page-label :page1)) ^js context (api/create-context "TEST") + + _ (set! st/state store) + context (api/create-context "TEST") + + ^js file (. context -currentFile) ^js page (. context -currentPage) ^js shape (.createRectangle context) get-shape-path - #(vector :workspace-data :pages-index (aget page "$id") :objects (aget shape "$id") %)] + #(vector :files (aget file "$id") :data :pages-index (aget page "$id") :objects (aget shape "$id") %)] (t/testing "Basic shape properites" (t/testing " - name" @@ -214,9 +217,9 @@ (t/testing " - strokes" (set! (.-strokes shape) #js [#js {:strokeColor "#fabada" :strokeOpacity 1 :strokeWidth 5}]) (t/is (= (get-in @store (get-shape-path :strokes)) [{:stroke-color "#fabada" :stroke-opacity 1 :stroke-width 5}])) - (t/is (= (-> (. shape -strokes) (aget 0) (aget "strokeColor")) "#fabada")) - (t/is (= (-> (. shape -strokes) (aget 0) (aget "strokeOpacity")) 1)) - (t/is (= (-> (. shape -strokes) (aget 0) (aget "strokeWidth")) 5)))) + (t/is (= (-> (. ^js shape -strokes) (aget 0) (aget "strokeColor")) "#fabada")) + (t/is (= (-> (. ^js shape -strokes) (aget 0) (aget "strokeOpacity")) 1)) + (t/is (= (-> (. ^js shape -strokes) (aget 0) (aget "strokeWidth")) 5)))) (t/testing "Relative properties" (let [board (.createBoard context)] @@ -227,29 +230,28 @@ (.appendChild board shape) (t/testing " - boardX" - (set! (.-boardX shape) 10) - (t/is (m/close? (.-boardX shape) 10)) + (set! (.-boardX ^js shape) 10) + (t/is (m/close? (.-boardX ^js shape) 10)) (t/is (m/close? (.-x shape) 110)) (t/is (m/close? (get-in @store (get-shape-path :x)) 110))) (t/testing " - boardY" - (set! (.-boardY shape) 20) - (t/is (m/close? (.-boardY shape) 20)) + (set! (.-boardY ^js shape) 20) + (t/is (m/close? (.-boardY ^js shape) 20)) (t/is (m/close? (.-y shape) 220)) (t/is (m/close? (get-in @store (get-shape-path :y)) 220))) (t/testing " - parentX" - (set! (.-parentX shape) 30) - (t/is (m/close? (.-parentX shape) 30)) + (set! (.-parentX ^js shape) 30) + (t/is (m/close? (.-parentX ^js shape) 30)) (t/is (m/close? (.-x shape) 130)) (t/is (m/close? (get-in @store (get-shape-path :x)) 130))) (t/testing " - parentY" - (set! (.-parentY shape) 40) - (t/is (m/close? (.-parentY shape) 40)) + (set! (.-parentY ^js shape) 40) + (t/is (m/close? (.-parentY ^js shape) 40)) (t/is (m/close? (.-y shape) 240)) (t/is (m/close? (get-in @store (get-shape-path :y)) 240))))) (t/testing "Clone") (t/testing "Remove"))) - diff --git a/frontend/test/frontend_tests/test_helpers_shapes.cljs b/frontend/test/frontend_tests/test_helpers_shapes.cljs index 11e552542..46ad76b40 100644 --- a/frontend/test/frontend_tests/test_helpers_shapes.cljs +++ b/frontend/test/frontend_tests/test_helpers_shapes.cljs @@ -41,9 +41,8 @@ store (the/prepare-store state done (fn [new-state] - (t/is (= (get-in new-state [:workspace-data - :recent-colors]) - [color]))))] + (let [colors (:recent-colors new-state)] + (t/is (= colors [color])))))] (ptk/emit! store diff --git a/frontend/test/frontend_tests/tokens/helpers/state.cljs b/frontend/test/frontend_tests/tokens/helpers/state.cljs index 0593a2099..25fa2805b 100644 --- a/frontend/test/frontend_tests/tokens/helpers/state.cljs +++ b/frontend/test/frontend_tests/tokens/helpers/state.cljs @@ -1,6 +1,7 @@ (ns frontend-tests.tokens.helpers.state (:require [app.common.types.tokens-lib :as ctob] + [app.main.data.helpers :as dsh] [app.main.ui.workspace.tokens.style-dictionary :as sd] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -22,10 +23,11 @@ (ptk/reify ::end+ ptk/WatchEvent (watch [_ state _] - (->> (rx/from (-> (get-in state [:workspace-data :tokens-lib]) - (ctob/get-active-themes-set-tokens) - (sd/resolve-tokens+))) - (rx/mapcat #(rx/of (end))))))) + (let [data (dsh/lookup-file-data state)] + (->> (rx/from (-> (get data :tokens-lib) + (ctob/get-active-themes-set-tokens) + (sd/resolve-tokens+))) + (rx/mapcat #(rx/of (end)))))))) (defn stop-on "Helper function to be used with async version of run-store. diff --git a/frontend/test/frontend_tests/tokens/helpers/tokens.cljs b/frontend/test/frontend_tests/tokens/helpers/tokens.cljs index 5bfe1ed70..eb6c4b7cd 100644 --- a/frontend/test/frontend_tests/tokens/helpers/tokens.cljs +++ b/frontend/test/frontend_tests/tokens/helpers/tokens.cljs @@ -9,7 +9,8 @@ (ctob/get-active-themes-set-tokens) (get name))) -(defn apply-token-to-shape [file shape-label token-label attributes] +(defn apply-token-to-shape + [file shape-label token-label attributes] (let [first-page-id (get-in file [:data :pages 0]) shape-id (thi/id shape-label) token (get-token file token-label) diff --git a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs index 08376d33f..30e623d98 100644 --- a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs +++ b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs @@ -45,8 +45,8 @@ (t/testing "applies token to shape and updates shape attributes to resolved value" (t/async done - (let [file (setup-file-with-tokens) - store (ths/setup-store file) + (let [file (setup-file-with-tokens) + store (ths/setup-store file) rect-1 (cths/get-shape file :rect-1) events [(wtch/apply-token {:shape-ids [(:id rect-1)] :attributes #{:r1 :r2 :r3 :r4} @@ -55,12 +55,14 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token (toht/get-token file' "borderRadius.md") + (let [file' (ths/get-file-from-state new-state) + token (toht/get-token file' "borderRadius.md") rect-1' (cths/get-shape file' :rect-1)] + (t/testing "shape `:applied-tokens` got updated" (t/is (some? (:applied-tokens rect-1'))) (t/is (= (:r1 (:applied-tokens rect-1')) (:name token)))) + (t/testing "shape radius got update to the resolved token value." (t/is (= (:r1 rect-1') 24)))))))))) @@ -82,7 +84,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) token (toht/get-token file' "borderRadius.md") rect-1' (cths/get-shape file' :rect-1)] (t/testing "shape `:applied-tokens` got updated" @@ -113,7 +115,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) token-sm (toht/get-token file' "borderRadius.sm") token-md (toht/get-token file' "borderRadius.md") rect-1' (cths/get-shape file' :rect-1)] @@ -145,7 +147,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) token-target' (toht/get-token file' "rotation.medium") rect-1' (cths/get-shape file' :rect-1)] (t/is (some? (:applied-tokens rect-1'))) @@ -173,7 +175,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) token-target' (toht/get-token file' "dimensions.sm") rect-1' (cths/get-shape file' :rect-1)] (t/testing "shape `:applied-tokens` got updated" @@ -203,7 +205,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) token-target' (toht/get-token file' "sizing.sm") rect-1' (cths/get-shape file' :rect-1)] (t/testing "shape `:applied-tokens` got updated" @@ -252,7 +254,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) rect-1' (cths/get-shape file' :rect-1) rect-2' (cths/get-shape file' :rect-2) rect-3' (cths/get-shape file' :rect-3) @@ -288,7 +290,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) token-target' (toht/get-token file' "rotation.medium") rect-1' (cths/get-shape file' :rect-1)] (t/is (some? (:applied-tokens rect-1'))) @@ -319,7 +321,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) token-target' (toht/get-token file' "stroke-width.sm") rect-with-stroke' (cths/get-shape file' :rect-1) rect-without-stroke' (cths/get-shape file' :rect-2)] @@ -345,7 +347,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) token-2' (toht/get-token file' "borderRadius.md") rect-1' (cths/get-shape file' :rect-1) rect-2' (cths/get-shape file' :rect-2)] @@ -375,7 +377,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) rect-with-token' (cths/get-shape file' :rect-1) rect-without-token' (cths/get-shape file' :rect-2) rect-with-other-token' (cths/get-shape file' :rect-3)] @@ -408,7 +410,7 @@ (tohs/run-store-async store done events (fn [new-state] - (let [file' (ths/get-file-from-store new-state) + (let [file' (ths/get-file-from-state new-state) target-token (toht/get-token file' "borderRadius.sm") rect-with-other-token-1' (cths/get-shape file' :rect-1) rect-without-token' (cths/get-shape file' :rect-2)