Integrate objects-map and introduce file feature flags

This commit is contained in:
Andrey Antukh 2022-10-06 18:47:16 +02:00 committed by Andrés Moya
parent 69f084e1df
commit 951b3eb4fe
21 changed files with 406 additions and 264 deletions

View file

@ -352,10 +352,13 @@
[v] [v]
(and (pgarray? v) (= "uuid" (.getBaseTypeName ^PgArray v)))) (and (pgarray? v) (= "uuid" (.getBaseTypeName ^PgArray v))))
;; TODO rename to decode-pgarray-into
(defn decode-pgarray (defn decode-pgarray
([v] (some->> ^PgArray v .getArray vec)) ([v] (decode-pgarray v []))
([v in] (some->> ^PgArray v .getArray (into in))) ([v in]
([v in xf] (some->> ^PgArray v .getArray (into in xf)))) (into in (some-> ^PgArray v .getArray)))
([v in xf]
(into in xf (some-> ^PgArray v .getArray))))
(defn pgarray->set (defn pgarray->set
[v] [v]

View file

@ -254,6 +254,9 @@
{:name "0081-add-deleted-at-index-to-file-table" {:name "0081-add-deleted-at-index-to-file-table"
:fn (mg/resource "app/migrations/sql/0081-add-deleted-at-index-to-file-table.sql")} :fn (mg/resource "app/migrations/sql/0081-add-deleted-at-index-to-file-table.sql")}
{:name "0082-add-features-column-to-file-table"
:fn (mg/resource "app/migrations/sql/0082-add-features-column-to-file-table.sql")}
]) ])

View file

@ -0,0 +1,2 @@
ALTER TABLE file
ADD COLUMN features text[] DEFAULT NULL;

View file

@ -8,6 +8,8 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.exceptions :as ex] [app.common.exceptions :as ex]
[app.common.files.features :as ffeat]
[app.common.logging :as l]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.pages.migrations :as pmg] [app.common.pages.migrations :as pmg]
[app.common.spec :as us] [app.common.spec :as us]
@ -24,6 +26,7 @@
[app.rpc.semaphore :as rsem] [app.rpc.semaphore :as rsem]
[app.storage.impl :as simpl] [app.storage.impl :as simpl]
[app.util.blob :as blob] [app.util.blob :as blob]
[app.util.objects-map :as omap]
[app.util.services :as sv] [app.util.services :as sv]
[app.util.time :as dt] [app.util.time :as dt]
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
@ -44,10 +47,11 @@
;; --- Mutation: Create File ;; --- Mutation: Create File
(s/def ::features ::us/set-of-strings)
(s/def ::is-shared ::us/boolean) (s/def ::is-shared ::us/boolean)
(s/def ::create-file (s/def ::create-file
(s/keys :req-un [::profile-id ::name ::project-id] (s/keys :req-un [::profile-id ::name ::project-id]
:opt-un [::id ::is-shared ::components-v2])) :opt-un [::id ::is-shared ::features ::components-v2]))
(sv/defmethod ::create-file (sv/defmethod ::create-file
[{:keys [pool] :as cfg} {:keys [profile-id project-id] :as params}] [{:keys [pool] :as cfg} {:keys [profile-id project-id] :as params}]
@ -68,27 +72,37 @@
(defn create-file (defn create-file
[conn {:keys [id name project-id is-shared data revn [conn {:keys [id name project-id is-shared data revn
modified-at deleted-at ignore-sync-until modified-at deleted-at ignore-sync-until
components-v2] components-v2 features]
:or {is-shared false revn 0} :or {is-shared false revn 0}
:as params}] :as params}]
(let [id (or id (:id data) (uuid/next)) (let [id (or id (:id data) (uuid/next))
data (or data (ctf/make-file-data id components-v2))
file (db/insert! conn :file ;; BACKWARD COMPATIBILITY with the components-v2 param
(d/without-nils features (cond-> (or features #{})
{:id id components-v2 (conj "components/v2"))
:project-id project-id
:name name data (or data
:revn revn (binding [ffeat/*current* features]
:is-shared is-shared (ctf/make-file-data id)))
:data (blob/encode data)
:ignore-sync-until ignore-sync-until features (db/create-array conn "text" features)
:modified-at modified-at file (db/insert! conn :file
:deleted-at deleted-at}))] (d/without-nils
{:id id
:project-id project-id
:name name
:revn revn
:is-shared is-shared
:data (blob/encode data)
:features features
:ignore-sync-until ignore-sync-until
:modified-at modified-at
:deleted-at deleted-at}))]
(->> (assoc params :file-id id :role :owner) (->> (assoc params :file-id id :role :owner)
(create-file-role conn)) (create-file-role conn))
(assoc file :data data))) (-> file files/decode-row)))
;; --- Mutation: Rename File ;; --- Mutation: Rename File
@ -309,24 +323,59 @@
(s/def ::update-file (s/def ::update-file
(s/and (s/and
(s/keys :req-un [::id ::session-id ::profile-id ::revn] (s/keys :req-un [::id ::session-id ::profile-id ::revn]
:opt-un [::changes ::changes-with-metadata ::components-v2]) :opt-un [::changes ::changes-with-metadata ::components-v2 ::features])
(fn [o] (fn [o]
(or (contains? o :changes) (or (contains? o :changes)
(contains? o :changes-with-metadata))))) (contains? o :changes-with-metadata)))))
(def ^:private sql:retrieve-file
"SELECT f.*, p.team_id
FROM file AS f
JOIN project AS p ON (p.id = f.project_id)
WHERE f.id = ?
AND (f.deleted_at IS NULL OR
f.deleted_at > now())
FOR KEY SHARE")
(sv/defmethod ::update-file (sv/defmethod ::update-file
{::rsem/queue :update-file} {::rsem/queue :update-file}
[{:keys [pool] :as cfg} {:keys [id profile-id] :as params}] [{:keys [pool] :as cfg} {:keys [id profile-id components-v2] :as params}]
(db/with-atomic [conn pool] (db/with-atomic [conn pool]
(db/xact-lock! conn id) (db/xact-lock! conn id)
(let [{:keys [id] :as file} (db/get-by-id conn :file id {:for-key-share true}) (let [file (db/exec-one! conn [sql:retrieve-file id])
team-id (retrieve-team-id conn (:project-id file))] features' (:features params #{})
(files/check-edition-permissions! conn profile-id id) features (db/decode-pgarray (:features file) features')
(with-meta
(update-file (assoc cfg :conn conn) ;; BACKWARD COMPATIBILITY with the components-v2 parameter
(assoc params :file file)) features (cond-> features
{::audit/props {:project-id (:project-id file) components-v2 (conj "components/v2"))
:team-id team-id}}))))
file (assoc file :features features)]
(when-not file
(ex/raise :type :not-found
:code :object-not-found
:hint (format "file with id '%s' does not exists" id)))
;; If features are specified from params and the final feature
;; set is different than the persisted one, update it on the
;; database.
(when (not= features features')
(let [features (db/create-array conn "text" features)]
(db/update! conn :file
{:features features}
{:id id})))
(binding [ffeat/*current* features
ffeat/*wrap-objects-fn* (if (features "storate/objects-map")
omap/wrap
identity)]
(files/check-edition-permissions! conn profile-id (:id file))
(with-meta
(update-file (assoc cfg :conn conn)
(assoc params :file file))
{::audit/props {:project-id (:project-id file)
:team-id (:team-id file)}})))))
(defn- take-snapshot? (defn- take-snapshot?
"Defines the rule when file `data` snapshot should be saved." "Defines the rule when file `data` snapshot should be saved."
@ -347,7 +396,7 @@
(defn- update-file (defn- update-file
[{:keys [conn metrics] :as cfg} [{:keys [conn metrics] :as cfg}
{:keys [file changes changes-with-metadata session-id profile-id components-v2] :as params}] {:keys [file changes changes-with-metadata session-id profile-id] :as params}]
(when (> (:revn params) (when (> (:revn params)
(:revn file)) (:revn file))
@ -378,7 +427,8 @@
(assoc :id (:id file)) (assoc :id (:id file))
(pmg/migrate-data)) (pmg/migrate-data))
components-v2
(contains? ffeat/*current* "components/v2")
(ctf/migrate-to-components-v2) (ctf/migrate-to-components-v2)
:always :always
@ -455,7 +505,8 @@
:changes changes}) :changes changes})
(when (and (:is-shared file) (seq lchanges)) (when (and (:is-shared file) (seq lchanges))
(let [team-id (retrieve-team-id conn (:project-id file))] (let [team-id (or (:team-id file)
(retrieve-team-id conn (:project-id file)))]
;; Asynchronously publish message to the msgbus ;; Asynchronously publish message to the msgbus
(mbus/pub! msgbus (mbus/pub! msgbus
:topic team-id :topic team-id

View file

@ -227,29 +227,34 @@
(d/index-by :object-id :data)))))) (d/index-by :object-id :data))))))
(defn retrieve-file (defn retrieve-file
[{:keys [pool] :as cfg} id components-v2] [{:keys [pool] :as cfg} id features]
(let [file (->> (db/get-by-id pool :file id) (let [file (->> (db/get-by-id pool :file id)
(decode-row) (decode-row)
(pmg/migrate-file))] (pmg/migrate-file))]
(if components-v2 (if (contains? features "components/v2")
(update file :data ctf/migrate-to-components-v2) (update file :data ctf/migrate-to-components-v2)
(if (get-in file [:data :options :components-v2]) (if (dm/get-in file [:data :options :components-v2])
(ex/raise :type :restriction (ex/raise :type :restriction
:code :feature-disabled :code :feature-disabled
:hint "tried to open a components-v2 file with feature disabled") :hint "tried to open a components/v2 file with feature disabled")
file)))) file))))
(s/def ::features ::us/set-of-strings)
(s/def ::file (s/def ::file
(s/keys :req-un [::profile-id ::id] (s/keys :req-un [::profile-id ::id]
:opt-un [::components-v2])) :opt-un [::features ::components-v2]))
(sv/defmethod ::file (sv/defmethod ::file
"Retrieve a file by its ID. Only authenticated users." "Retrieve a file by its ID. Only authenticated users."
[{:keys [pool] :as cfg} {:keys [profile-id id components-v2] :as params}] [{:keys [pool] :as cfg} {:keys [profile-id id features components-v2] :as params}]
(let [perms (get-permissions pool profile-id id)] (let [perms (get-permissions pool profile-id id)
;; BACKWARD COMPATIBILTY with the components-v2 parameter
features (cond-> (or features #{})
components-v2 (conj features "components/v2"))]
(check-read-permissions! perms) (check-read-permissions! perms)
(let [file (retrieve-file cfg id components-v2) (let [file (retrieve-file cfg id features)
thumbs (retrieve-object-thumbnails cfg id)] thumbs (retrieve-object-thumbnails cfg id)]
(-> file (-> file
(assoc :thumbnails thumbs) (assoc :thumbnails thumbs)
@ -278,7 +283,7 @@
(s/def ::page (s/def ::page
(s/and (s/and
(s/keys :req-un [::profile-id ::file-id] (s/keys :req-un [::profile-id ::file-id]
:opt-un [::page-id ::object-id ::components-v2]) :opt-un [::page-id ::object-id ::features ::components-v2])
(fn [obj] (fn [obj]
(if (contains? obj :object-id) (if (contains? obj :object-id)
(contains? obj :page-id) (contains? obj :page-id)
@ -294,11 +299,15 @@
mandatory. mandatory.
Mainly used for rendering purposes." Mainly used for rendering purposes."
[{:keys [pool] :as cfg} {:keys [profile-id file-id page-id object-id components-v2] :as props}] [{:keys [pool] :as cfg} {:keys [profile-id file-id page-id object-id features components-v2] :as props}]
(check-read-permissions! pool profile-id file-id) (check-read-permissions! pool profile-id file-id)
(let [file (retrieve-file cfg file-id components-v2) (let [;; BACKWARD COMPATIBILTY with the components-v2 parameter
page-id (or page-id (-> file :data :pages first)) features (cond-> (or features #{})
page (get-in file [:data :pages-index page-id])] components-v2 (conj features "components/v2"))
file (retrieve-file cfg file-id features)
page-id (or page-id (-> file :data :pages first))
page (dm/get-in file [:data :pages-index page-id])]
(cond-> (prune-thumbnails page) (cond-> (prune-thumbnails page)
(uuid? object-id) (uuid? object-id)
@ -384,14 +393,17 @@
(s/def ::file-data-for-thumbnail (s/def ::file-data-for-thumbnail
(s/keys :req-un [::profile-id ::file-id] (s/keys :req-un [::profile-id ::file-id]
:opt-un [::components-v2])) :opt-un [::components-v2 ::features]))
(sv/defmethod ::file-data-for-thumbnail (sv/defmethod ::file-data-for-thumbnail
"Retrieves the data for generate the thumbnail of the file. Used "Retrieves the data for generate the thumbnail of the file. Used
mainly for render thumbnails on dashboard." mainly for render thumbnails on dashboard."
[{:keys [pool] :as cfg} {:keys [profile-id file-id components-v2] :as props}] [{:keys [pool] :as cfg} {:keys [profile-id file-id features components-v2] :as props}]
(check-read-permissions! pool profile-id file-id) (check-read-permissions! pool profile-id file-id)
(let [file (retrieve-file cfg file-id components-v2)] (let [;; BACKWARD COMPATIBILTY with the components-v2 parameter
features (cond-> (or features #{})
components-v2 (conj features "components/v2"))
file (retrieve-file cfg file-id features)]
{:file-id file-id {:file-id file-id
:revn (:revn file) :revn (:revn file)
:page (get-file-thumbnail-data cfg file)})) :page (get-file-thumbnail-data cfg file)}))
@ -567,8 +579,9 @@
;; --- Helpers ;; --- Helpers
(defn decode-row (defn decode-row
[{:keys [data changes] :as row}] [{:keys [data changes features] :as row}]
(when row (when row
(cond-> row (cond-> row
changes (assoc :changes (blob/decode changes)) features (assoc :features (db/decode-pgarray features))
data (assoc :data (blob/decode data))))) changes (assoc :changes (blob/decode changes))
data (assoc :data (blob/decode data)))))

View file

@ -23,8 +23,8 @@
(db/get-by-id pool :project id {:columns [:id :name :team-id]})) (db/get-by-id pool :project id {:columns [:id :name :team-id]}))
(defn- retrieve-bundle (defn- retrieve-bundle
[{:keys [pool] :as cfg} file-id profile-id components-v2] [{:keys [pool] :as cfg} file-id profile-id features]
(p/let [file (files/retrieve-file cfg file-id components-v2) (p/let [file (files/retrieve-file cfg file-id features)
project (retrieve-project pool (:project-id file)) project (retrieve-project pool (:project-id file))
libs (files/retrieve-file-libraries cfg false file-id) libs (files/retrieve-file-libraries cfg false file-id)
users (comments/get-file-comments-users pool file-id profile-id) users (comments/get-file-comments-users pool file-id profile-id)
@ -45,40 +45,49 @@
(s/def ::file-id ::us/uuid) (s/def ::file-id ::us/uuid)
(s/def ::profile-id ::us/uuid) (s/def ::profile-id ::us/uuid)
(s/def ::share-id ::us/uuid) (s/def ::share-id ::us/uuid)
(s/def ::features ::us/set-of-strings)
;; TODO: deprecated, should be removed when version >= 1.18
(s/def ::components-v2 ::us/boolean) (s/def ::components-v2 ::us/boolean)
(s/def ::view-only-bundle (s/def ::view-only-bundle
(s/keys :req-un [::file-id] :opt-un [::profile-id ::share-id ::components-v2])) (s/keys :req-un [::file-id]
:opt-un [::profile-id ::share-id ::features ::components-v2]))
(sv/defmethod ::view-only-bundle {:auth false} (sv/defmethod ::view-only-bundle {:auth false}
[{:keys [pool] :as cfg} {:keys [profile-id file-id share-id components-v2] :as params}] [{:keys [pool] :as cfg} {:keys [profile-id file-id share-id features components-v2] :as params}]
(p/let [slink (slnk/retrieve-share-link pool file-id share-id) (p/let [;; BACKWARD COMPATIBILTY with the components-v2 parameter
features (cond-> (or features #{})
components-v2 (conj features "components/v2"))
slink (slnk/retrieve-share-link pool file-id share-id)
perms (files/get-permissions pool profile-id file-id share-id) perms (files/get-permissions pool profile-id file-id share-id)
thumbs (files/retrieve-object-thumbnails cfg file-id) thumbs (files/retrieve-object-thumbnails cfg file-id)
bundle (p/-> (retrieve-bundle cfg file-id profile-id components-v2) bundle (p/-> (retrieve-bundle cfg file-id profile-id features)
(assoc :permissions perms) (assoc :permissions perms)
(assoc-in [:file :thumbnails] thumbs))] (assoc-in [:file :thumbnails] thumbs))]
;; When we have neither profile nor share, we just return a not ;; When we have neither profile nor share, we just return a not
;; found response to the user. ;; found response to the user.
(when (and (not profile-id) (do
(not slink)) (when (and (not profile-id)
(ex/raise :type :not-found (not slink))
:code :object-not-found)) (ex/raise :type :not-found
:code :object-not-found))
;; When we have only profile, we need to check read permissions ;; When we have only profile, we need to check read permissions
;; on file. ;; on file.
(when (and profile-id (not slink)) (when (and profile-id (not slink))
(files/check-read-permissions! pool profile-id file-id)) (files/check-read-permissions! pool profile-id file-id))
(cond-> bundle (cond-> bundle
(some? slink) (some? slink)
(assoc :share slink) (assoc :share slink)
(and (some? slink) (and (some? slink)
(not (contains? (:flags slink) "view-all-pages"))) (not (contains? (:flags slink) "view-all-pages")))
(update-in [:file :data] (fn [data] (update-in [:file :data] (fn [data]
(let [allowed-pages (:pages slink)] (let [allowed-pages (:pages slink)]
(-> data (-> data
(update :pages (fn [pages] (filterv #(contains? allowed-pages %) pages))) (update :pages (fn [pages] (filterv #(contains? allowed-pages %) pages)))
(update :pages-index (fn [index] (select-keys index allowed-pages)))))))))) (update :pages-index (fn [index] (select-keys index allowed-pages)))))))))))

View file

@ -148,38 +148,41 @@
(defn create-profile* (defn create-profile*
([i] (create-profile* *pool* i {})) ([i] (create-profile* *pool* i {}))
([i params] (create-profile* *pool* i params)) ([i params] (create-profile* *pool* i params))
([conn i params] ([pool i params]
(let [params (merge {:id (mk-uuid "profile" i) (let [params (merge {:id (mk-uuid "profile" i)
:fullname (str "Profile " i) :fullname (str "Profile " i)
:email (str "profile" i ".test@nodomain.com") :email (str "profile" i ".test@nodomain.com")
:password "123123" :password "123123"
:is-demo false} :is-demo false}
params)] params)]
(->> params (with-open [conn (db/open pool)]
(cmd.auth/create-profile conn) (->> params
(cmd.auth/create-profile-relations conn))))) (cmd.auth/create-profile conn)
(cmd.auth/create-profile-relations conn))))))
(defn create-project* (defn create-project*
([i params] (create-project* *pool* i params)) ([i params] (create-project* *pool* i params))
([conn i {:keys [profile-id team-id] :as params}] ([pool i {:keys [profile-id team-id] :as params}]
(us/assert uuid? profile-id) (us/assert uuid? profile-id)
(us/assert uuid? team-id) (us/assert uuid? team-id)
(->> (merge {:id (mk-uuid "project" i) (with-open [conn (db/open pool)]
:name (str "project" i)} (->> (merge {:id (mk-uuid "project" i)
params) :name (str "project" i)}
(#'projects/create-project conn)))) params)
(#'projects/create-project conn)))))
(defn create-file* (defn create-file*
([i params] ([i params]
(create-file* *pool* i params)) (create-file* *pool* i params))
([conn i {:keys [profile-id project-id] :as params}] ([pool i {:keys [profile-id project-id] :as params}]
(us/assert uuid? profile-id) (us/assert uuid? profile-id)
(us/assert uuid? project-id) (us/assert uuid? project-id)
(#'files/create-file conn (with-open [conn (db/open pool)]
(merge {:id (mk-uuid "file" i) (#'files/create-file conn
:name (str "file" i) (merge {:id (mk-uuid "file" i)
:components-v2 true} :name (str "file" i)
params)))) :components-v2 true}
params)))))
(defn mark-file-deleted* (defn mark-file-deleted*
([params] (mark-file-deleted* *pool* params)) ([params] (mark-file-deleted* *pool* params))
@ -188,85 +191,95 @@
(defn create-team* (defn create-team*
([i params] (create-team* *pool* i params)) ([i params] (create-team* *pool* i params))
([conn i {:keys [profile-id] :as params}] ([pool i {:keys [profile-id] :as params}]
(us/assert uuid? profile-id) (us/assert uuid? profile-id)
(let [id (mk-uuid "team" i)] (with-open [conn (db/open pool)]
(teams/create-team conn {:id id (let [id (mk-uuid "team" i)]
:profile-id profile-id (teams/create-team conn {:id id
:name (str "team" i)})))) :profile-id profile-id
:name (str "team" i)})))))
(defn create-file-media-object* (defn create-file-media-object*
([params] (create-file-media-object* *pool* params)) ([params] (create-file-media-object* *pool* params))
([conn {:keys [name width height mtype file-id is-local media-id] ([pool {:keys [name width height mtype file-id is-local media-id]
:or {name "sample" width 100 height 100 mtype "image/svg+xml" is-local true}}] :or {name "sample" width 100 height 100 mtype "image/svg+xml" is-local true}}]
(db/insert! conn :file-media-object
{:id (uuid/next) (with-open [conn (db/open pool)]
:file-id file-id (db/insert! conn :file-media-object
:is-local is-local {:id (uuid/next)
:name name :file-id file-id
:media-id media-id :is-local is-local
:width width :name name
:height height :media-id media-id
:mtype mtype}))) :width width
:height height
:mtype mtype}))))
(defn link-file-to-library* (defn link-file-to-library*
([params] (link-file-to-library* *pool* params)) ([params] (link-file-to-library* *pool* params))
([conn {:keys [file-id library-id] :as params}] ([pool {:keys [file-id library-id] :as params}]
(#'files/link-file-to-library conn {:file-id file-id :library-id library-id}))) (with-open [conn (db/open pool)]
(#'files/link-file-to-library conn {:file-id file-id :library-id library-id}))))
(defn create-complaint-for (defn create-complaint-for
[conn {:keys [id created-at type]}] [pool {:keys [id created-at type]}]
(db/insert! conn :profile-complaint-report (with-open [conn (db/open pool)]
{:profile-id id (db/insert! conn :profile-complaint-report
:created-at (or created-at (dt/now)) {:profile-id id
:type (name type) :created-at (or created-at (dt/now))
:content (db/tjson {})})) :type (name type)
:content (db/tjson {})})))
(defn create-global-complaint-for (defn create-global-complaint-for
[conn {:keys [email type created-at]}] [pool {:keys [email type created-at]}]
(db/insert! conn :global-complaint-report (with-open [conn (db/open pool)]
{:email email (db/insert! conn :global-complaint-report
:type (name type) {:email email
:created-at (or created-at (dt/now)) :type (name type)
:content (db/tjson {})})) :created-at (or created-at (dt/now))
:content (db/tjson {})})))
(defn create-team-role* (defn create-team-role*
([params] (create-team-role* *pool* params)) ([params] (create-team-role* *pool* params))
([conn {:keys [team-id profile-id role] :or {role :owner}}] ([pool {:keys [team-id profile-id role] :or {role :owner}}]
(#'teams/create-team-role conn {:team-id team-id (with-open [conn (db/open pool)]
:profile-id profile-id (#'teams/create-team-role conn {:team-id team-id
:role role}))) :profile-id profile-id
:role role}))))
(defn create-project-role* (defn create-project-role*
([params] (create-project-role* *pool* params)) ([params] (create-project-role* *pool* params))
([conn {:keys [project-id profile-id role] :or {role :owner}}] ([pool {:keys [project-id profile-id role] :or {role :owner}}]
(#'projects/create-project-role conn {:project-id project-id (with-open [conn (db/open pool)]
:profile-id profile-id (#'projects/create-project-role conn {:project-id project-id
:role role}))) :profile-id profile-id
:role role}))))
(defn create-file-role* (defn create-file-role*
([params] (create-file-role* *pool* params)) ([params] (create-file-role* *pool* params))
([conn {:keys [file-id profile-id role] :or {role :owner}}] ([pool {:keys [file-id profile-id role] :or {role :owner}}]
(#'files/create-file-role conn {:file-id file-id (with-open [conn (db/open pool)]
:profile-id profile-id (#'files/create-file-role conn {:file-id file-id
:role role}))) :profile-id profile-id
:role role}))))
(defn update-file* (defn update-file*
([params] (update-file* *pool* params)) ([params] (update-file* *pool* params))
([conn {:keys [file-id changes session-id profile-id revn] ([pool {:keys [file-id changes session-id profile-id revn]
:or {session-id (uuid/next) revn 0}}] :or {session-id (uuid/next) revn 0}}]
(let [file (db/get-by-id conn :file file-id) (with-open [conn (db/open pool)]
msgbus (:app.msgbus/msgbus *system*) (let [file (db/get-by-id conn :file file-id)
metrics (:app.metrics/metrics *system*)] msgbus (:app.msgbus/msgbus *system*)
(#'files/update-file {:conn conn metrics (:app.metrics/metrics *system*)]
:msgbus msgbus (#'files/update-file {:conn conn
:metrics metrics} :msgbus msgbus
{:file file :metrics metrics}
:revn revn {:file file
:components-v2 true :revn revn
:changes changes :components-v2 true
:session-id session-id :changes changes
:profile-id profile-id})))) :session-id session-id
:profile-id profile-id})))))
;; --- RPC HELPERS ;; --- RPC HELPERS

View file

@ -0,0 +1,10 @@
;; 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.common.files.features)
(def ^:dynamic *current* #{})
(def ^:dynamic *wrap-objects-fn* identity)

View file

@ -347,27 +347,12 @@
;; -- Components ;; -- Components
(defmethod process-change :add-component (defmethod process-change :add-component
[data {:keys [id name path main-instance-id main-instance-page shapes]}] [data params]
(ctkl/add-component data (ctkl/add-component data params))
id
name
path
main-instance-id
main-instance-page
shapes))
(defmethod process-change :mod-component (defmethod process-change :mod-component
[data {:keys [id name path objects]}] [data params]
(update-in data [:components id] (ctkl/mod-component data params))
#(cond-> %
(some? name)
(assoc :name name)
(some? path)
(assoc :path path)
(some? objects)
(assoc :objects objects))))
(defmethod process-change :del-component (defmethod process-change :del-component
[data {:keys [id skip-undelete?]}] [data {:keys [id skip-undelete?]}]

View file

@ -8,6 +8,7 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.files.features :as ffeat]
[app.common.geom.matrix :as gmt] [app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
@ -50,10 +51,12 @@
(defn with-objects (defn with-objects
[changes objects] [changes objects]
(let [file-data (-> (ctf/make-file-data (uuid/next) uuid/zero true) (let [fdata (binding [ffeat/*current* #{"components/v2"}]
(assoc-in [:pages-index uuid/zero :objects] objects))] (ctf/make-file-data (uuid/next) uuid/zero))
(vary-meta changes assoc ::file-data file-data fdata (assoc-in fdata [:pages-index uuid/zero :objects] objects)]
::applied-changes-count 0))) (vary-meta changes assoc
::file-data fdata
::applied-changes-count 0)))
(defn with-library-data (defn with-library-data
[changes data] [changes data]
@ -268,7 +271,7 @@
:page-id (::page-id (meta changes)) :page-id (::page-id (meta changes))
:parent-id (:parent-id shape) :parent-id (:parent-id shape)
:shapes [(:id shape)] :shapes [(:id shape)]
:index idx})))] :index idx})))]
(-> changes (-> changes
(update :redo-changes conj set-parent-change) (update :redo-changes conj set-parent-change)
@ -592,7 +595,7 @@
:main-instance-page main-instance-page :main-instance-page main-instance-page
:shapes new-shapes}) :shapes new-shapes})
(into (map mk-change) updated-shapes)))) (into (map mk-change) updated-shapes))))
(update :undo-changes (update :undo-changes
(fn [undo-changes] (fn [undo-changes]
(-> undo-changes (-> undo-changes
(d/preconj {:type :del-component (d/preconj {:type :del-component

View file

@ -9,7 +9,7 @@
(defn instance-root? (defn instance-root?
[shape] [shape]
(some? (:component-id shape))) (some? (:component-id shape)))
(defn instance-of? (defn instance-of?
[shape file-id component-id] [shape file-id component-id]
(and (some? (:component-id shape)) (and (some? (:component-id shape))

View file

@ -2,30 +2,52 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; 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/. ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;; ;;
;; Copyright (c) UXBOX Labs SL ;; Copyright (c) KELEIDOS INC
(ns app.common.types.components-list (ns app.common.types.components-list
(:require (:require
[app.common.data :as d])) [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.features :as feat]))
(defn components-seq (defn components-seq
[file-data] [file-data]
(vals (:components file-data))) (vals (:components file-data)))
(defn add-component (defn add-component
[file-data id name path main-instance-id main-instance-page shapes] [file-data {:keys [id name path main-instance-id main-instance-page shapes]}]
(let [components-v2 (get-in file-data [:options :components-v2])] (let [components-v2 (dm/get-in file-data [:options :components-v2])
wrap-object-fn feat/*wrap-objects-fn*]
(cond-> file-data (cond-> file-data
:always :always
(assoc-in [:components id] (assoc-in [:components id]
{:id id {:id id
:name name :name name
:path path :path path
:objects (d/index-by :id shapes)}) :objects (->> shapes
(d/index-by :id)
(wrap-object-fn))})
components-v2 components-v2
(update-in [:components id] assoc :main-instance-id main-instance-id (update-in [:components id] assoc
:main-instance-page main-instance-page)))) :main-instance-id main-instance-id
:main-instance-page main-instance-page))))
(defn mod-component
[file-data {:keys [id name path objects]}]
(let [wrap-objects-fn feat/*wrap-objects-fn*]
(update-in file-data [:components id]
(fn [component]
(let [objects (some-> objects wrap-objects-fn)]
(cond-> component
(some? name)
(assoc :name name)
(some? path)
(assoc :path path)
(some? objects)
(assoc :objects objects)))))))
(defn get-component (defn get-component
[file-data component-id] [file-data component-id]

View file

@ -6,6 +6,7 @@
(ns app.common.types.container (ns app.common.types.container
(:require (:require
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.spec :as us] [app.common.spec :as us]
@ -41,8 +42,8 @@
(us/assert uuid? id) (us/assert uuid? id)
(-> (if (= type :page) (-> (if (= type :page)
(get-in file [:pages-index id]) (dm/get-in file [:pages-index id])
(get-in file [:components id])) (dm/get-in file [:components id]))
(assoc :type type))) (assoc :type type)))
(defn get-shape (defn get-shape

View file

@ -7,6 +7,8 @@
(ns app.common.types.file (ns app.common.types.file
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.features :as ffeat]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.pages.common :refer [file-version]] [app.common.pages.common :refer [file-version]]
@ -65,16 +67,16 @@
:pages-index {}}) :pages-index {}})
(defn make-file-data (defn make-file-data
([file-id components-v2] ([file-id]
(make-file-data file-id (uuid/next) components-v2)) (make-file-data file-id (uuid/next)))
([file-id page-id components-v2] ([file-id page-id]
(let [page (ctp/make-empty-page page-id "Page-1")] (let [page (ctp/make-empty-page page-id "Page-1")]
(cond-> (-> empty-file-data (cond-> (-> empty-file-data
(assoc :id file-id) (assoc :id file-id)
(ctpl/add-page page)) (ctpl/add-page page))
components-v2 (contains? ffeat/*current* "components/v2")
(assoc-in [:options :components-v2] true))))) (assoc-in [:options :components-v2] true)))))
;; Helpers ;; Helpers
@ -108,7 +110,7 @@
([libraries component-id] ([libraries component-id]
(some #(ctkl/get-component (:data %) component-id) (vals libraries))) (some #(ctkl/get-component (:data %) component-id) (vals libraries)))
([libraries library-id component-id] ([libraries library-id component-id]
(ctkl/get-component (get-in libraries [library-id :data]) component-id))) (ctkl/get-component (dm/get-in libraries [library-id :data]) component-id)))
(defn delete-component (defn delete-component
"Delete a component and store it to be able to be recovered later. "Delete a component and store it to be able to be recovered later.
@ -118,7 +120,7 @@
(delete-component file-data component-id false)) (delete-component file-data component-id false))
([file-data component-id skip-undelete?] ([file-data component-id skip-undelete?]
(let [components-v2 (get-in file-data [:options :components-v2]) (let [components-v2 (dm/get-in file-data [:options :components-v2])
add-to-deleted-components add-to-deleted-components
(fn [file-data] (fn [file-data]
@ -144,12 +146,12 @@
(defn get-deleted-component (defn get-deleted-component
"Retrieve a component that has been deleted but still is in the safe store." "Retrieve a component that has been deleted but still is in the safe store."
[file-data component-id] [file-data component-id]
(get-in file-data [:deleted-components component-id])) (dm/get-in file-data [:deleted-components component-id]))
(defn restore-component (defn restore-component
"Recover a deleted component and put it again in place." "Recover a deleted component and put it again in place."
[file-data component-id] [file-data component-id]
(let [component (-> (get-in file-data [:deleted-components component-id]) (let [component (-> (dm/get-in file-data [:deleted-components component-id])
(dissoc :main-instance-x :main-instance-y))] (dissoc :main-instance-x :main-instance-y))]
(cond-> file-data (cond-> file-data
(some? component) (some? component)
@ -242,7 +244,7 @@
[file-data] [file-data]
(let [components (ctkl/components-seq file-data)] (let [components (ctkl/components-seq file-data)]
(if (or (empty? components) (if (or (empty? components)
(get-in file-data [:options :components-v2])) (dm/get-in file-data [:options :components-v2]))
(assoc-in file-data [:options :components-v2] true) (assoc-in file-data [:options :components-v2] true)
(let [grid-gap 50 (let [grid-gap 50
@ -342,12 +344,12 @@
copy-component copy-component
(fn [file-data] (fn [file-data]
(ctkl/add-component file-data (ctkl/add-component file-data
(:id component) {:id (:id component)
(:name component) :name (:name component)
(:path component) :path (:path component)
(:id main-instance-shape) :main-instance-id (:id main-instance-shape)
page-id :main-instance-page page-id
(vals (:objects component)))) :shapes (vals (:objects component))}))
; Change all existing instances to point to the local file ; Change all existing instances to point to the local file
remap-instances remap-instances
@ -500,10 +502,10 @@
component-file (when component-file-id (get libraries component-file-id nil)) component-file (when component-file-id (get libraries component-file-id nil))
component (when component-id component (when component-id
(if component-file (if component-file
(get-in component-file [:data :components component-id]) (dm/get-in component-file [:data :components component-id])
(get components component-id))) (get components component-id)))
component-shape (when (and component (:shape-ref shape)) component-shape (when (and component (:shape-ref shape))
(get-in component [:objects (:shape-ref shape)]))] (dm/get-in component [:objects (:shape-ref shape)]))]
(str/format " %s--> %s%s%s" (str/format " %s--> %s%s%s"
(cond (:component-root? shape) "#" (cond (:component-root? shape) "#"
(:component-id shape) "@" (:component-id shape) "@"
@ -518,7 +520,7 @@
component-file-id (:component-file shape) component-file-id (:component-file shape)
component-file (when component-file-id (get libraries component-file-id nil)) component-file (when component-file-id (get libraries component-file-id nil))
component (if component-file component (if component-file
(get-in component-file [:data :components component-id]) (dm/get-in component-file [:data :components component-id])
(get components component-id))] (get components component-id))]
(str/format " (%s%s)" (str/format " (%s%s)"
(when component-file (str/format "<%s> " (:name component-file))) (when component-file (str/format "<%s> " (:name component-file)))

View file

@ -7,6 +7,7 @@
(ns app.common.types.page (ns app.common.types.page
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.files.features :as ffeat]
[app.common.types.page.flow :as ctpf] [app.common.types.page.flow :as ctpf]
[app.common.types.page.grid :as ctpg] [app.common.types.page.grid :as ctpg]
[app.common.types.page.guide :as ctpu] [app.common.types.page.guide :as ctpu]
@ -48,9 +49,11 @@
(defn make-empty-page (defn make-empty-page
[id name] [id name]
(assoc empty-page-data (let [wrap-fn ffeat/*wrap-objects-fn*]
:id id (-> empty-page-data
:name name)) (assoc :id id)
(assoc :name name)
(update :objects wrap-fn))))
;; --- Helpers for flow ;; --- Helpers for flow

View file

@ -2,32 +2,29 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; 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/. ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;; ;;
;; Copyright (c) UXBOX Labs SL ;; Copyright (c) KALEIDOS INC
(ns app.common.types.pages-list (ns app.common.types.pages-list
(:require (:require
[app.common.data :as d] [app.common.data.macros :as dm]
[app.common.pages.helpers :as cph])) [app.common.pages.helpers :as cph]))
(defn get-page (defn get-page
[file-data id] [file-data id]
(get-in file-data [:pages-index id])) (dm/get-in file-data [:pages-index id]))
(defn add-page (defn add-page
[file-data page] [file-data {:keys [id index] :as page}]
(let [index (:index page) (-> file-data
page (dissoc page :index) ;; It's legitimate to add a page that is already there, for
;; example in an idempotent changes operation.
; It's legitimate to add a page that is already there, (update :pages (fn [pages]
; for example in an idempotent changes operation. (let [exists? (some (partial = id) pages)]
add-if-not-exists (fn [pages id] (cond
(cond exists? pages
(d/seek #(= % id) pages) pages (nil? index) (conj pages id)
(nil? index) (conj pages id) :else (cph/insert-at-index pages index [id])))))
:else (cph/insert-at-index pages index [id])))] (update :pages-index assoc id (dissoc page :index))))
(-> file-data
(update :pages add-if-not-exists (:id page))
(update :pages-index assoc (:id page) page))))
(defn pages-seq (defn pages-seq
[file-data] [file-data]
@ -42,4 +39,3 @@
(-> file-data (-> file-data
(update :pages (fn [pages] (filterv #(not= % page-id) pages))) (update :pages (fn [pages] (filterv #(not= % page-id) pages)))
(update :pages-index dissoc page-id))) (update :pages-index dissoc page-id)))

View file

@ -6,16 +6,22 @@
(ns app.common.pages-test (ns app.common.pages-test
(:require (:require
[clojure.test :as t] [app.common.files.features :as ffeat]
[clojure.pprint :refer [pprint]]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.types.file :as ctf] [app.common.types.file :as ctf]
[app.common.uuid :as uuid])) [app.common.uuid :as uuid]
[clojure.pprint :refer [pprint]]
[clojure.test :as t]))
(defn- make-file-data
[file-id page-id]
(binding [ffeat/*current* #{"components/v2"}]
(ctf/make-file-data file-id page-id)))
(t/deftest process-change-set-option (t/deftest process-change-set-option
(let [file-id (uuid/custom 2 2) (let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1) page-id (uuid/custom 1 1)
data (ctf/make-file-data file-id page-id true)] data (make-file-data file-id page-id)]
(t/testing "Sets option single" (t/testing "Sets option single"
(let [chg {:type :set-option (let [chg {:type :set-option
:page-id page-id :page-id page-id
@ -81,7 +87,7 @@
(t/deftest process-change-add-obj (t/deftest process-change-add-obj
(let [file-id (uuid/custom 2 2) (let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1) page-id (uuid/custom 1 1)
data (ctf/make-file-data file-id page-id true) data (make-file-data file-id page-id)
id-a (uuid/custom 2 1) id-a (uuid/custom 2 1)
id-b (uuid/custom 2 2) id-b (uuid/custom 2 2)
id-c (uuid/custom 2 3)] id-c (uuid/custom 2 3)]
@ -135,7 +141,7 @@
(t/deftest process-change-mod-obj (t/deftest process-change-mod-obj
(let [file-id (uuid/custom 2 2) (let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1) page-id (uuid/custom 1 1)
data (ctf/make-file-data file-id page-id true)] data (make-file-data file-id page-id)]
(t/testing "simple mod-obj" (t/testing "simple mod-obj"
(let [chg {:type :mod-obj (let [chg {:type :mod-obj
:page-id page-id :page-id page-id
@ -162,7 +168,7 @@
(let [file-id (uuid/custom 2 2) (let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1) page-id (uuid/custom 1 1)
id (uuid/custom 2 1) id (uuid/custom 2 1)
data (ctf/make-file-data file-id page-id true) data (make-file-data file-id page-id)
data (-> data data (-> data
(assoc-in [:pages-index page-id :objects uuid/zero :shapes] [id]) (assoc-in [:pages-index page-id :objects uuid/zero :shapes] [id])
(assoc-in [:pages-index page-id :objects id] (assoc-in [:pages-index page-id :objects id]
@ -206,7 +212,7 @@
file-id (uuid/custom 2 2) file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1) page-id (uuid/custom 1 1)
data (ctf/make-file-data file-id page-id true) data (make-file-data file-id page-id)
data (update-in data [:pages-index page-id :objects] data (update-in data [:pages-index page-id :objects]
#(-> % #(-> %
@ -450,7 +456,7 @@
:obj {:type :rect :obj {:type :rect
:name "Shape 3"}} :name "Shape 3"}}
] ]
data (ctf/make-file-data file-id page-id true) data (make-file-data file-id page-id)
data (cp/process-changes data changes)] data (cp/process-changes data changes)]
(t/testing "preserve order on multiple shape mov 1" (t/testing "preserve order on multiple shape mov 1"
@ -557,7 +563,7 @@
:parent-id group-1-id :parent-id group-1-id
:shapes [shape-1-id shape-2-id]}] :shapes [shape-1-id shape-2-id]}]
data (ctf/make-file-data file-id page-id true) data (make-file-data file-id page-id)
data (cp/process-changes data changes)] data (cp/process-changes data changes)]
(t/testing "case 1" (t/testing "case 1"

View file

@ -6,16 +6,22 @@
(ns app.common.test-helpers.files (ns app.common.test-helpers.files
(:require (:require
[app.common.geom.point :as gpt] [app.common.files.features :as ffeat]
[app.common.types.components-list :as ctkl] [app.common.geom.point :as gpt]
[app.common.types.colors-list :as ctcl] [app.common.types.colors-list :as ctcl]
[app.common.types.container :as ctn] [app.common.types.components-list :as ctkl]
[app.common.types.file :as ctf] [app.common.types.container :as ctn]
[app.common.types.pages-list :as ctpl] [app.common.types.file :as ctf]
[app.common.types.shape :as cts] [app.common.types.pages-list :as ctpl]
[app.common.types.shape-tree :as ctst] [app.common.types.shape :as cts]
[app.common.types.typographies-list :as ctyl] [app.common.types.shape-tree :as ctst]
[app.common.uuid :as uuid])) [app.common.types.typographies-list :as ctyl]
[app.common.uuid :as uuid]))
(defn- make-file-data
[file-id page-id]
(binding [ffeat/*current* #{"components/v2"}]
(ctf/make-file-data file-id page-id)))
(def ^:private idmap (atom {})) (def ^:private idmap (atom {}))
@ -33,7 +39,7 @@
([file-id page-id props] ([file-id page-id props]
(merge {:id file-id (merge {:id file-id
:name (get props :name "File1") :name (get props :name "File1")
:data (ctf/make-file-data file-id page-id true)} :data (make-file-data file-id page-id)}
props))) props)))
(defn sample-shape (defn sample-shape
@ -81,12 +87,12 @@
#(reduce (fn [page shape] (ctst/set-shape page shape)) #(reduce (fn [page shape] (ctst/set-shape page shape))
% %
updated-shapes)) updated-shapes))
(ctkl/add-component (:id component-shape) (ctkl/add-component {:id (:id component-shape)
(:name component-shape) :name (:name component-shape)
"" :path ""
shape-id :main-instance-id shape-id
page-id :main-instance-page page-id
component-shapes)))))) :shapes component-shapes}))))))
(defn sample-instance (defn sample-instance
[file label page-id library component-id] [file label page-id library component-id]

View file

@ -765,9 +765,14 @@
(let [{:keys [on-success on-error] (let [{:keys [on-success on-error]
:or {on-success identity :or {on-success identity
on-error rx/throw}} (meta params) on-error rx/throw}} (meta params)
name (name (gensym (str (tr "dashboard.new-file-prefix") " ")))
components-v2 (features/active-feature? state :components-v2) name (name (gensym (str (tr "dashboard.new-file-prefix") " ")))
params (assoc params :name name :components-v2 components-v2)] features (cond-> #{}
(features/active-feature? state :components-v2)
(conj "components/v2"))
params (-> params
(assoc :name name)
(assoc :features features))]
(->> (rp/mutation! :create-file params) (->> (rp/mutation! :create-file params)
(rx/tap on-success) (rx/tap on-success)

View file

@ -7,6 +7,7 @@
(ns app.main.data.workspace.persistence (ns app.main.data.workspace.persistence
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.logging :as log] [app.common.logging :as log]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.pages.changes-spec :as pcs] [app.common.pages.changes-spec :as pcs]
@ -137,14 +138,16 @@
(ptk/reify ::persist-changes (ptk/reify ::persist-changes
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [components-v2 (features/active-feature? state :components-v2) (let [features (cond-> #{}
sid (:session-id state) (features/active-feature? state :components-v2)
file (get state :workspace-file) (conj "components/v2"))
params {:id (:id file) sid (:session-id state)
:revn (:revn file) file (get state :workspace-file)
:session-id sid params {:id (:id file)
:changes-with-metadata (into [] changes) :revn (:revn file)
:components-v2 components-v2}] :session-id sid
:changes-with-metadata (into [] changes)
:features features}]
(when (= file-id (:id params)) (when (= file-id (:id params))
(->> (rp/mutation :update-file params) (->> (rp/mutation :update-file params)
@ -180,15 +183,17 @@
(ptk/reify ::persist-synchronous-changes (ptk/reify ::persist-synchronous-changes
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [components-v2 (features/active-feature? state :components-v2) (let [features (cond-> #{}
sid (:session-id state) (features/active-feature? state :components-v2)
file (get-in state [:workspace-libraries file-id]) (conj "components/v2"))
sid (:session-id state)
file (dm/get-in state [:workspace-libraries file-id])
params {:id (:id file) params {:id (:id file)
:revn (:revn file) :revn (:revn file)
:session-id sid :session-id sid
:changes changes :changes changes
:components-v2 components-v2}] :features features}]
(when (:id params) (when (:id params)
(->> (rp/mutation :update-file params) (->> (rp/mutation :update-file params)
@ -220,6 +225,9 @@
(ptk/reify ::changes-persisted (ptk/reify ::changes-persisted
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
;; NOTE: we don't set the file features context here because
;; there are no useful context for code that need to be executed
;; on the frontend side
(let [changes (group-by :page-id changes)] (let [changes (group-by :page-id changes)]
(if (= file-id (:current-file-id state)) (if (= file-id (:current-file-id state))
(-> state (-> state
@ -238,7 +246,6 @@
(update-in [:workspace-libraries file-id :data] (update-in [:workspace-libraries file-id :data]
cp/process-changes changes))))))) cp/process-changes changes)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Data Fetching & Uploading ;; Data Fetching & Uploading
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -278,8 +285,11 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [share-id (-> state :viewer-local :share-id) (let [share-id (-> state :viewer-local :share-id)
components-v2 (features/active-feature? state :components-v2)] features (cond-> #{}
(->> (rx/zip (rp/query! :file-raw {:id file-id :components-v2 components-v2}) (features/active-feature? state :components-v2)
(conj "components/v2"))]
(->> (rx/zip (rp/query! :file-raw {:id file-id :features features})
(rp/query! :team-users {:file-id file-id}) (rp/query! :team-users {:file-id file-id})
(rp/query! :project {:id project-id}) (rp/query! :project {:id project-id})
(rp/query! :file-libraries {:file-id file-id}) (rp/query! :file-libraries {:file-id file-id})

View file

@ -72,4 +72,3 @@
(doseq [f features-list] (doseq [f features-list]
(when (not= f :components-v2) (when (not= f :components-v2)
(toggle-feature! f))))) (toggle-feature! f)))))