diff --git a/backend/src/app/rpc/commands/files_create.clj b/backend/src/app/rpc/commands/files_create.clj index 9b5e1598d..73c8d7909 100644 --- a/backend/src/app/rpc/commands/files_create.clj +++ b/backend/src/app/rpc/commands/files_create.clj @@ -120,7 +120,7 @@ ;; to lost team features updating ;; When newly computed features does not match exactly with - ;; the features defined on team row, we update it. + ;; the features defined on team row, we update it (when (not= features (:features team)) (let [features (db/create-array conn "text" features)] (db/update! conn :team diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 9939108aa..589c431ce 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -334,7 +334,8 @@ (rx/take-until stopper-s)))))) (defn initialize-workspace - [file-id] + [team-id file-id] + (assert (uuid? team-id) "expected valud uuid for `team-id`") (assert (uuid? file-id) "expected valud uuid for `file-id`") (ptk/reify ::initialize-workspace ptk/UpdateEvent @@ -410,7 +411,7 @@ (unchecked-set ug/global "name" name))))) (defn finalize-workspace - [file-id] + [_team-id file-id] (ptk/reify ::finalize-workspace ptk/UpdateEvent (update [_ state] @@ -444,8 +445,9 @@ (ptk/reify ::reload-current-file ptk/WatchEvent (watch [_ state _] - (let [file-id (:current-file-id state)] - (rx/of (initialize-workspace file-id)))))) + (let [file-id (:current-file-id state) + team-id (:current-team-id state)] + (rx/of (initialize-workspace team-id file-id)))))) ;; Make this event callable through dynamic resolution (defmethod ptk/resolve ::reload-current-file [_ _] (reload-current-file)) @@ -488,18 +490,25 @@ (defn initialize-page [file-id page-id] (assert (uuid? file-id) "expected valid uuid for `file-id`") + (assert (uuid? page-id) "expected valid uuid for `page-id`") (ptk/reify ::initialize-page ptk/WatchEvent (watch [_ state _] (if-let [page (dsh/lookup-page state file-id page-id)] - (rx/concat (rx/of (initialize-page* file-id page-id page) - (dwth/watch-state-changes file-id page-id) - (dwl/watch-component-changes)) - (let [profile (:profile state) - props (get profile :props)] - (when (not (:workspace-visited props)) - (rx/of (select-frame-tool file-id page-id))))) + (rx/concat + (rx/of (initialize-page* file-id page-id page) + (dwth/watch-state-changes file-id page-id) + (dwl/watch-component-changes)) + (let [profile (:profile state) + props (get profile :props)] + (when (not (:workspace-visited props)) + (rx/of (select-frame-tool file-id page-id))))) + + ;; NOTE: this redirect is necessary for cases where user + ;; explicitly passes an non-existing page-id on the url + ;; params, so on check it we can detect that there are no data + ;; for the page and redirect user to an existing page (rx/of (dcm/go-to-workspace :file-id file-id ::rt/replace true)))))) (defn finalize-page diff --git a/frontend/src/app/main/data/workspace/versions.cljs b/frontend/src/app/main/data/workspace/versions.cljs index ee710883a..f444d29a8 100644 --- a/frontend/src/app/main/data/workspace/versions.cljs +++ b/frontend/src/app/main/data/workspace/versions.cljs @@ -10,6 +10,7 @@ [app.common.data.macros :as dm] [app.common.schema :as sm] [app.main.data.event :as ev] + [app.main.data.helpers :as dsh] [app.main.data.persistence :as dwp] [app.main.data.workspace :as dw] [app.main.data.workspace.thumbnails :as th] @@ -97,7 +98,8 @@ (ptk/reify ::restore-version ptk/WatchEvent (watch [_ state _] - (let [file-id (:current-file-id state)] + (let [file-id (:current-file-id state) + team-id (:current-team-id state)] (rx/concat (rx/of ::dwp/force-persist (dw/remove-layout-flag :document-history)) @@ -106,7 +108,7 @@ (rx/take 1) (rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id})) (rx/tap #(th/clear-queue!)) - (rx/map #(dw/initialize-workspace file-id))) + (rx/map #(dw/initialize-workspace team-id file-id))) (case origin :version (rx/of (ptk/event ::ev/event {::ev/name "restore-pin-version"})) @@ -200,21 +202,24 @@ (ptk/reify ::restore-version-from-plugins ptk/WatchEvent - (watch [_ _ _] - (rx/concat - (rx/of (ptk/event ::ev/event {::ev/name "restore-version-plugin"}) - ::dwp/force-persist) + (watch [_ state _] + ;; FIXME: revisit this + (let [file (dsh/lookup-file state file-id) + team-id (:team-id file)] + (rx/concat + (rx/of (ptk/event ::ev/event {::ev/name "restore-version-plugin"}) + ::dwp/force-persist) - ;; FIXME: we should abstract this - (->> (rx/from-atom refs/persistence-state {:emit-current-value? true}) - (rx/filter #(or (nil? %) (= :saved %))) - (rx/take 1) - (rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id})) - (rx/map #(dw/initialize-workspace file-id))) + ;; FIXME: we should abstract this + (->> (rx/from-atom refs/persistence-state {:emit-current-value? true}) + (rx/filter #(or (nil? %) (= :saved %))) + (rx/take 1) + (rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id})) + (rx/map #(dw/initialize-workspace team-id file-id))) - (->> (rx/of 1) - (rx/tap resolve) - (rx/ignore)))))) + (->> (rx/of 1) + (rx/tap resolve) + (rx/ignore))))))) diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs index d6de04f20..83349799a 100644 --- a/frontend/src/app/main/ui/workspace.cljs +++ b/frontend/src/app/main/ui/workspace.cljs @@ -9,6 +9,7 @@ (: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] @@ -45,9 +46,10 @@ (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) - page-id (:id page) + page-id (get page :id) {:keys [vport] :as wlocal} (mf/deref refs/workspace-local) {:keys [options-mode]} wglobal @@ -120,10 +122,46 @@ :overlay true :file-loading true}]) +(defn- make-team-ref + [team-id] + (l/derived (fn [state] + (let [teams (get state :teams)] + (get teams team-id))) + st/state)) + +(defn- make-file-ref + [file-id] + (l/derived (fn [state] + ;; NOTE: for ensure ordering of execution, we need to + ;; wait the file initialization completly success until + ;; mark this file availablea and unlock the rendering + ;; of the following components + (when (= (get state :current-file-id) file-id) + (let [files (get state :files) + file (get files file-id)] + (-> file + (dissoc :data) + (assoc ::has-data (contains? file :data)))))) + st/state)) + +(defn- make-page-ref + [file-id page-id] + (l/derived (fn [state] + (let [current-page-id (get state :current-page-id)] + ;; NOTE: for ensure ordering of execution, we need to + ;; wait the page initialization completly success until + ;; mark this file availablea and unlock the rendering + ;; of the following components + (when (= current-page-id page-id) + (dsh/lookup-page state file-id page-id)))) + st/state)) + (mf/defc workspace-page* {::mf/private true} [{:keys [page-id file-id file layout wglobal]}] - (let [page (mf/deref refs/workspace-page)] + (let [page-ref (mf/with-memo [file-id page-id] + (make-page-ref file-id page-id)) + page (mf/deref page-ref)] (mf/with-effect [] (let [focus-out #(st/emit! (dw/workspace-focus-lost)) @@ -133,8 +171,7 @@ (mf/with-effect [file-id page-id] (st/emit! (dw/initialize-page file-id page-id)) (fn [] - (when page-id - (st/emit! (dw/finalize-page file-id page-id))))) + (st/emit! (dw/finalize-page file-id page-id)))) (if (some? page) [:> workspace-content* {:file file @@ -143,18 +180,9 @@ :layout layout}] [:> workspace-loader*]))) -(def ^:private ref:file-without-data - (l/derived (fn [file] - (-> file - (dissoc :data) - (assoc ::has-data (contains? file :data)))) - refs/file - =)) - (mf/defc workspace* - {::mf/props :obj - ::mf/wrap [mf/memo]} - [{:keys [project-id file-id page-id layout-name]}] + {::mf/wrap [mf/memo]} + [{:keys [team-id project-id file-id page-id layout-name]}] (let [file-id (hooks/use-equal-memo file-id) page-id (hooks/use-equal-memo page-id) @@ -162,8 +190,15 @@ layout (mf/deref refs/workspace-layout) wglobal (mf/deref refs/workspace-global) - team (mf/deref refs/team) - file (mf/deref ref:file-without-data) + team-ref (mf/with-memo [team-id] + (make-team-ref team-id)) + file-ref (mf/with-memo [file-id] + (make-file-ref file-id)) + + team (mf/deref team-ref) + file (mf/deref file-ref) + + file-loaded? (get file ::has-data) file-name (:name file) permissions (:permissions team) @@ -187,14 +222,14 @@ (when file-name (dom/set-html-title (tr "title.workspace" file-name)))) - (mf/with-effect [file-id] - (st/emit! (dw/initialize-workspace file-id)) + (mf/with-effect [team-id file-id] + (st/emit! (dw/initialize-workspace team-id file-id)) (fn [] (st/emit! ::dps/force-persist - (dw/finalize-workspace file-id)))) + (dw/finalize-workspace team-id file-id)))) - (mf/with-effect [file page-id] - (when-not page-id + (mf/with-effect [file-id page-id file-loaded?] + (when (and file-loaded? (not page-id)) (st/emit! (dcm/go-to-workspace :file-id file-id ::rt/replace true)))) [:> (mf/provider ctx/current-project-id) {:value project-id} @@ -208,8 +243,7 @@ :style {:background-color background-color :touch-action "none"}} [:> context-menu*] - - (if (::has-data file) + (if (and file-loaded? page-id) [:> workspace-page* {:page-id page-id :file-id file-id