From 94677f2f7e01d143ad2f1c4789122d5399b4301a Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 25 Mar 2017 19:35:54 +0100 Subject: [PATCH] Improve history handling on frontend. --- frontend/src/uxbox/main/data/history.cljs | 301 ++++++++++-------- frontend/src/uxbox/main/data/pages.cljs | 3 + frontend/src/uxbox/main/data/workspace.cljs | 37 +-- frontend/src/uxbox/main/refs.cljs | 19 +- frontend/src/uxbox/main/ui/workspace.cljs | 16 +- .../src/uxbox/main/ui/workspace/sidebar.cljs | 60 ++-- .../main/ui/workspace/sidebar/drawtools.cljs | 3 +- .../main/ui/workspace/sidebar/history.cljs | 137 ++++---- .../main/ui/workspace/sidebar/layers.cljs | 2 - .../main/ui/workspace/sidebar/sitemap.cljs | 5 +- frontend/src/uxbox/util/data.cljs | 20 +- 11 files changed, 322 insertions(+), 281 deletions(-) diff --git a/frontend/src/uxbox/main/data/history.cljs b/frontend/src/uxbox/main/data/history.cljs index 5cb1a0f98..ada0cdde6 100644 --- a/frontend/src/uxbox/main/data/history.cljs +++ b/frontend/src/uxbox/main/data/history.cljs @@ -2,160 +2,207 @@ ;; 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) 2016 Andrey Antukh +;; Copyright (c) 2016-2017 Andrey Antukh (ns uxbox.main.data.history - (:require [cuerdas.core :as str] - [beicon.core :as rx] - [lentes.core :as l] + (:require [beicon.core :as rx] [potok.core :as ptk] - [uxbox.util.router :as r] - [uxbox.main.repo :as rp] - [uxbox.util.i18n :refer (tr)] - [uxbox.util.forms :as sc] [uxbox.main.data.pages :as udp] - [uxbox.main.store :as st] - [uxbox.util.time :as dt] - [uxbox.util.data :refer (without-keys - replace-by-id - index-by)])) + [uxbox.main.repo :as rp] + [uxbox.util.data :refer [replace-by-id + index-by]])) -;; --- Watch Page Changes +;; --- Initialize History State -(declare fetch-page-history) -(declare fetch-pinned-page-history) +(declare fetch-history) +(declare fetch-pinned-history) + +(deftype Initialize [page-id] + ptk/UpdateEvent + (update [_ state] + (let [data {:section :main + :selected nil + :pinned #{} + :items #{} + :byver {}}] + (assoc-in state [:workspace :history] data))) -(deftype WatchPageChanges [id] ptk/WatchEvent (watch [_ state stream] - (let [stopper (->> stream - (rx/filter #(= % ::udp/stop-page-watcher)) + (let [page-id (get-in state [:workspace :page]) + stopper (->> stream + (rx/filter #(= % ::stop-changes-watcher)) (rx/take 1))] - (->> stream - (rx/take-until stopper) - (rx/filter udp/page-persisted?) - (rx/debounce 500) - (rx/flat-map #(rx/of (fetch-page-history id) - (fetch-pinned-page-history id))))))) + (rx/merge + (->> stream + (rx/take-until stopper) + (rx/filter udp/page-persisted?) + (rx/flat-map #(rx/of (fetch-history page-id) + (fetch-pinned-history page-id)))) + (rx/of (fetch-history page-id) + (fetch-pinned-history page-id)))))) -(defn watch-page-changes - [id] - (WatchPageChanges. id)) +(defn initialize + [page-id] + {:pre [(uuid? page-id)]} + (Initialize. page-id)) ;; --- Pinned Page History Fetched -(declare update-history-index) - -(defrecord PinnedPageHistoryFetched [history] +(deftype PinnedPageHistoryFetched [items] ptk/UpdateEvent (update [_ state] - (-> state - (assoc-in [:workspace :history :pinned-items] (mapv :version history)) - (update-history-index history true)))) + (let [items-map (index-by items :version) + items-set (into #{} items)] + (update-in state [:workspace :history] + (fn [history] + (-> history + (assoc :pinned items-set) + (update :byver merge items-map))))))) + +(defn pinned-page-history-fetched + [items] + (PinnedPageHistoryFetched. items)) ;; --- Fetch Pinned Page History -(defrecord FetchPinnedPageHistory [id] +(deftype FetchPinnedPageHistory [id] ptk/WatchEvent (watch [_ state s] - (letfn [(on-success [{history :payload}] - (->PinnedPageHistoryFetched (into [] history)))] - (let [params {:page id :pinned true}] - (->> (rp/req :fetch/page-history params) - (rx/map on-success)))))) + (let [params {:page id :pinned true}] + (->> (rp/req :fetch/page-history params) + (rx/map :payload) + (rx/map pinned-page-history-fetched))))) -(defn fetch-pinned-page-history +(defn fetch-pinned-history [id] - (->FetchPinnedPageHistory id)) + {:pre [(uuid? id)]} + (FetchPinnedPageHistory. id)) ;; --- Page History Fetched -(defrecord PageHistoryFetched [history append?] +(deftype PageHistoryFetched [items] ptk/UpdateEvent (update [_ state] - (letfn [(update-counters [state items] - (-> (assoc state :min-version (apply min items)) - (assoc :max-version (apply max items)))) + (let [versions (into #{} (map :version) items) + items-map (index-by items :version) + min-version (apply min versions) + max-version (apply max versions)] + (update-in state [:workspace :history] + (fn [history] + (-> history + (assoc :min-version min-version) + (assoc :max-version max-version) + (update :byver merge items-map) + (update :items #(reduce conj % items)))))))) - (update-lists [state items] - (if append? - (update state :items #(reduce conj %1 items)) - (assoc state :items items)))] +;; TODO: add spec to history items - (let [items (mapv :version history) - hstate (-> (get-in state [:workspace :history] {}) - (update-counters items) - (update-lists items))] - (-> state - (assoc-in [:workspace :history] hstate) - (update-history-index history append?)))))) +(defn page-history-fetched + [items] + (PageHistoryFetched. items)) ;; --- Fetch Page History -(defrecord FetchPageHistory [id since max] +(deftype FetchPageHistory [page-id since max] ptk/WatchEvent (watch [_ state s] - (letfn [(on-success [{history :payload}] - (let [history (into [] history)] - (->PageHistoryFetched history (not (nil? since)))))] - (let [params (merge - {:page id :max (or max 15)} - (when since {:since since}))] - (->> (rp/req :fetch/page-history params) - (rx/map on-success)))))) + (let [params (merge {:page page-id + :max (or max 15)} + (when since + {:since since}))] + (->> (rp/req :fetch/page-history params) + (rx/map :payload) + (rx/map page-history-fetched))))) -(defn fetch-page-history +(defn fetch-history ([id] - (fetch-page-history id nil)) - ([id params] - (map->FetchPageHistory (assoc params :id id)))) + (fetch-history id nil)) + ([id {:keys [since max]}] + {:pre [(uuid? id)]} + (FetchPageHistory. id since max))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Context Aware Events +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; --- Select Section + +(deftype SelectSection [section] + ptk/UpdateEvent + (update [_ state] + (assoc-in state [:workspace :history :section] section))) + +(defn select-section + [section] + {:pre [(keyword? section)]} + (SelectSection. section)) + +;; --- Load More + +(deftype LoadMore [] + ptk/WatchEvent + (watch [_ state stream] + (let [page-id (get-in state [:workspace :page]) + since (get-in state [:workspace :history :min-version])] + (rx/of (fetch-history page-id {:since since}))))) + +(defn load-more + [] + (LoadMore.)) ;; --- Select Page History -(defrecord SelectPageHistory [version] +(deftype SelectPageHistory [version] ptk/UpdateEvent (update [_ state] - (let [item (get-in state [:workspace :history :by-version version]) + (let [history (get-in state [:workspace :history]) + item (get-in history [:byver version]) page (get-in state [:pages (:page item)]) - page (assoc page - :history true - :data (:data item))] + + page (-> (get-in state [:pages (:page item)]) + (assoc :history true + :data (:data item)))] (-> state (udp/assoc-page page) (assoc-in [:workspace :history :selected] version))))) (defn select-page-history [version] + {:pre [(integer? version)]} (SelectPageHistory. version)) -;; --- Apply selected history +;; --- Apply Selected History -(defrecord ApplySelectedHistory [id] +(deftype ApplySelectedHistory [] ptk/UpdateEvent (update [_ state] - (-> state - (update-in [:pages id] dissoc :history) - (assoc-in [:workspace :history :selected] nil))) + (let [page-id (get-in state [:workspace :page])] + (-> state + (update-in [:pages page-id] dissoc :history) + (assoc-in [:workspace :history :selected] nil)))) ptk/WatchEvent (watch [_ state s] - (rx/of (udp/persist-page id)))) + (let [page-id (get-in state [:workspace :page])] + (rx/of (udp/persist-page page-id))))) (defn apply-selected-history - [id] - (ApplySelectedHistory. id)) + [] + (ApplySelectedHistory.)) ;; --- Deselect Page History -(defrecord DeselectPageHistory [id ^:mutable noop] +(deftype DeselectPageHistory [^:mutable noop] ptk/UpdateEvent (update [_ state] - (let [selected (get-in state [:workspace :history :selected])] + (let [page-id (get-in state [:workspace :page]) + selected (get-in state [:workspace :history :selected])] (if (nil? selected) (do (set! noop true) state) - (let [packed (get-in state [:packed-pages id])] + (let [packed (get-in state [:packed-pages page-id])] (-> (udp/assoc-page state packed) (assoc-in [:workspace :history :deselecting] true) (assoc-in [:workspace :history :selected] nil)))))) @@ -168,18 +215,35 @@ (rx/delay 500))))) (defn deselect-page-history - [id] - {:pre [(uuid? id)]} - (DeselectPageHistory. id false)) + [] + (DeselectPageHistory. false)) + + ;; --- Refresh Page History + +(deftype RefreshHistory [] + ptk/WatchEvent + (watch [_ state stream] + (let [page-id (get-in state [:workspace :page]) + history (get-in state [:workspace :history]) + maxitems (count (:items history))] + (rx/of (fetch-history page-id {:max maxitems}) + (fetch-pinned-history page-id))))) + +(defn refres-history + [] + (RefreshHistory.)) ;; --- History Item Updated -(defrecord HistoryItemUpdated [item] +(deftype HistoryItemUpdated [item] ptk/UpdateEvent (update [_ state] - (-> state - (update-in [:workspace :history :items] replace-by-id item) - (update-in [:workspace :history :pinned-items] replace-by-id item)))) + (update-in state [:workspace :history] + (fn [history] + (-> history + (update :items #(into #{} (replace-by-id item) %)) + (update :pinned #(into #{} (replace-by-id item) %)) + (assoc-in [:byver (:id item)] item)))))) (defn history-updated? [item] @@ -189,33 +253,18 @@ [item] (HistoryItemUpdated. item)) -;; --- Refresh Page History - -(defrecord RefreshPageHistory [id] - ptk/WatchEvent - (watch [_ state s] - (let [history (get-in state [:workspace :history]) - maxitems (count (:items history))] - (rx/of (fetch-page-history id {:max maxitems}) - (fetch-pinned-page-history id))))) - -(defn refres-page-history - [id] - (RefreshPageHistory. id)) - ;; --- Update History Item -(defrecord UpdateHistoryItem [item] +(deftype UpdateHistoryItem [item] ptk/WatchEvent - (watch [_ state s] - (letfn [(on-success [{item :payload}] - (->HistoryItemUpdated item))] - (rx/merge - (->> (rp/req :update/page-history item) - (rx/map on-success)) - (->> (rx/filter history-updated? s) - (rx/take 1) - (rx/map #(refres-page-history (:page item)))))))) + (watch [_ state stream] + (rx/concat + (->> (rp/req :update/page-history item) + (rx/map :payload) + (rx/map history-updated)) + (->> (rx/filter history-updated? stream) + (rx/take 1) + (rx/map refres-history))))) (defn update-history-item [item] @@ -223,7 +272,7 @@ ;; --- Forward to Next Version -(defrecord ForwardToNextVersion [] +(deftype ForwardToNextVersion [] ptk/WatchEvent (watch [_ state s] (let [workspace (:workspace state) @@ -237,7 +286,7 @@ (rx/of (select-page-history (inc version))) (> (inc version) (:max-version history)) - (rx/of (deselect-page-history (:page workspace))) + (rx/of (deselect-page-history)) :else (rx/empty))))) @@ -248,7 +297,7 @@ ;; --- Backwards to Previous Version -(defrecord BackwardsToPreviousVersion [] +(deftype BackwardsToPreviousVersion [] ptk/WatchEvent (watch [_ state s] (let [workspace (:workspace state) @@ -265,7 +314,7 @@ (let [since (:min-version history) page (:page workspace) params {:since since}] - (rx/of (fetch-page-history page params) + (rx/of (fetch-history page params) (select-page-history (dec version))))) :else @@ -274,13 +323,3 @@ (defn backwards-to-previous-version [] (BackwardsToPreviousVersion.)) - -;; --- Helpers - -(defn- update-history-index - [state history append?] - (let [index (index-by history :version)] - (if append? - (update-in state [:workspace :history :by-version] merge index) - (assoc-in state [:workspace :history :by-version] index)))) - diff --git a/frontend/src/uxbox/main/data/pages.cljs b/frontend/src/uxbox/main/data/pages.cljs index a8b9924a9..413491136 100644 --- a/frontend/src/uxbox/main/data/pages.cljs +++ b/frontend/src/uxbox/main/data/pages.cljs @@ -262,6 +262,9 @@ ;; --- Page Persisted (deftype PagePersisted [data] + IDeref + (-deref [_] data) + ptk/UpdateEvent (update [_ state] (let [{:keys [id version]} data] diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 3ccb4ec29..04c3c9eea 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -8,7 +8,6 @@ (:require [cljs.spec :as s] [beicon.core :as rx] [potok.core :as ptk] - [lentes.core :as l] [uxbox.main.store :as st] [uxbox.main.constants :as c] [uxbox.main.lenses :as ul] @@ -47,16 +46,17 @@ (declare initialize-alignment) -(defrecord InitializeWorkspace [project-id page-id] +(defrecord Initialize [project-id page-id] ptk/UpdateEvent (update [_ state] - (let [default-flags #{:sitemap :drawtools :layers :element-options :rules}] + (let [default-flags #{:sitemap :drawtools :layers :element-options :rules} + default-flags #{:document-history}] (if (:workspace state) (update state :workspace merge {:project project-id :page page-id :selected #{} - :flags default-flags + ;; :flags default-flags :drawing nil :drawing-tool nil :tooltip nil}) @@ -77,21 +77,15 @@ ;; Activate loaded if page is not fetched. (when-not page (reset! st/loader true)) - (rx/merge - (if page - (rx/of (initialize-alignment page-id)) - (rx/merge - (rx/of (udp/fetch-pages project-id)) - (->> (rx/filter udp/pages-fetched? stream) - (rx/take 1) - (rx/do #(reset! st/loader false)) - (rx/map #(initialize-alignment page-id))))) - - ;; Initial history loading - ;; FIXME: move this to the history sidebar component - (rx/of - (udh/fetch-page-history page-id) - (udh/fetch-pinned-page-history page-id))))) + (if page + (rx/of (initialize-alignment page-id)) + (rx/merge + (rx/of (udp/fetch-pages project-id)) + (->> stream + (rx/filter udp/pages-fetched?) + (rx/take 1) + (rx/do #(reset! st/loader false)) + (rx/map #(initialize-alignment page-id))))))) ptk/EffectEvent (effect [_ state stream] @@ -104,7 +98,7 @@ [project page] {:pre [(uuid? project) (uuid? page)]} - (InitializeWorkspace. project page)) + (Initialize. project page)) ;; --- Workspace Tooltips @@ -306,8 +300,6 @@ ;; --- Grid Alignment -(declare initialize-alignment?) - (defrecord InitializeAlignment [id] ptk/WatchEvent (watch [_ state stream] @@ -327,6 +319,7 @@ (defn initialize-alignment [id] + {:pre [(uuid? id)]} (InitializeAlignment. id)) ;; --- Update Metadata diff --git a/frontend/src/uxbox/main/refs.cljs b/frontend/src/uxbox/main/refs.cljs index 7fe687174..c62a97237 100644 --- a/frontend/src/uxbox/main/refs.cljs +++ b/frontend/src/uxbox/main/refs.cljs @@ -9,21 +9,20 @@ (:require [lentes.core :as l] [beicon.core :as rx] [uxbox.main.constants :as c] - [uxbox.main.store :as st] - [uxbox.main.lenses :as ul])) + [uxbox.main.store :as st])) ;; --- Helpers (defn resolve-project "Retrieve the current project." [state] - (let [id (l/focus ul/selected-project state)] - (get-in state [:projects id]))) + (let [project-id (get-in state [:workspace :project])] + (get-in state [:projects project-id]))) (defn resolve-page [state] - (let [id (l/focus ul/selected-page state)] - (get-in state [:pages id]))) + (let [page-id (get-in state [:workspace :page])] + (get-in state [:pages page-id]))) (defn- resolve-project-pages [state] @@ -34,13 +33,19 @@ (sort-by get-order)))) (def workspace - (l/derive ul/workspace st/state)) + (-> (l/key :workspace) + (l/derive st/state))) (def selected-project "Ref to the current selected project." (-> (l/lens resolve-project) (l/derive st/state))) +(def selected-project-id + "Ref to the current selected project id." + (-> (l/key :project) + (l/derive selected-project))) + (def selected-project-pages (-> (l/lens resolve-project-pages) (l/derive st/state))) diff --git a/frontend/src/uxbox/main/ui/workspace.cljs b/frontend/src/uxbox/main/ui/workspace.cljs index 2cbe577b8..7cc0360ed 100644 --- a/frontend/src/uxbox/main/ui/workspace.cljs +++ b/frontend/src/uxbox/main/ui/workspace.cljs @@ -7,7 +7,6 @@ (ns uxbox.main.ui.workspace (:require [beicon.core :as rx] - [potok.core :as ptk] [lentes.core :as l] [uxbox.main.store :as st] [uxbox.main.constants :as c] @@ -55,7 +54,7 @@ (st/emit! (udp/watch-page-changes pageid) (udu/watch-page-changes pageid) - (udh/watch-page-changes pageid)) + #_(udh/watch-page-changes pageid)) (assoc own ::sub sub))) @@ -74,7 +73,7 @@ ::udp/stop-page-watcher (udp/watch-page-changes pageid) (udu/watch-page-changes pageid) - (udh/watch-page-changes pageid))) + #_(udh/watch-page-changes pageid))) state)) (defn- on-scroll @@ -110,10 +109,8 @@ :mixins [mx/static mx/reactive shortcuts-mixin]} - [own] + [own project-id page-id] (let [flags (mx/react refs/flags) - page (mx/react workspace-page-ref) - left-sidebar? (not (empty? (keep flags [:layers :sitemap :document-history]))) right-sidebar? (not (empty? (keep flags [:icons :drawtools @@ -133,8 +130,7 @@ :on-scroll on-scroll :on-wheel (partial on-wheel own)} - - (history-dialog page) + (history-dialog) ;; Rules (when (contains? flags :rules) @@ -151,6 +147,6 @@ ;; Aside (when left-sidebar? - (left-sidebar)) + (left-sidebar flags page-id)) (when right-sidebar? - (right-sidebar))]])) + (right-sidebar flags page-id))]])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar.cljs index 1580ed845..eb8dc83d6 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar.cljs @@ -6,46 +6,40 @@ ;; Copyright (c) 2015-2017 Juan de la Cruz (ns uxbox.main.ui.workspace.sidebar - (:require [lentes.core :as l] - [potok.core :as ptk] - [uxbox.main.store :as st] - [uxbox.main.refs :as refs] - [uxbox.main.ui.workspace.sidebar.options :refer (options-toolbox)] - [uxbox.main.ui.workspace.sidebar.layers :refer (layers-toolbox)] - [uxbox.main.ui.workspace.sidebar.sitemap :refer (sitemap-toolbox)] - [uxbox.main.ui.workspace.sidebar.history :refer (history-toolbox)] - [uxbox.main.ui.workspace.sidebar.icons :refer (icons-toolbox)] - [uxbox.main.ui.workspace.sidebar.drawtools :refer (draw-toolbox)] - [uxbox.util.router :as r] + (:require [uxbox.main.refs :as refs] + [uxbox.main.ui.workspace.sidebar.options :refer [options-toolbox]] + [uxbox.main.ui.workspace.sidebar.layers :refer [layers-toolbox]] + [uxbox.main.ui.workspace.sidebar.sitemap :refer [sitemap-toolbox]] + [uxbox.main.ui.workspace.sidebar.history :refer [history-toolbox]] + [uxbox.main.ui.workspace.sidebar.icons :refer [icons-toolbox]] + [uxbox.main.ui.workspace.sidebar.drawtools :refer [draw-toolbox]] [uxbox.util.mixins :as mx :include-macros true])) ;; --- Left Sidebar (Component) (mx/defc left-sidebar - {:mixins [mx/reactive mx/static]} - [] - (let [flags (mx/react refs/flags)] - [:aside#settings-bar.settings-bar.settings-bar-left - [:div.settings-bar-inside - (when (contains? flags :sitemap) - (sitemap-toolbox)) - (when (contains? flags :document-history) - (history-toolbox)) - (when (contains? flags :layers) - (layers-toolbox))]])) + {:mixins [mx/static]} + [flags page-id] + [:aside#settings-bar.settings-bar.settings-bar-left + [:div.settings-bar-inside + (when (contains? flags :sitemap) + (sitemap-toolbox page-id)) + (when (contains? flags :document-history) + (history-toolbox page-id)) + (when (contains? flags :layers) + (layers-toolbox))]]) ;; --- Right Sidebar (Component) (mx/defc right-sidebar - {:mixins [mx/reactive mx/static]} - [] - (let [flags (mx/react refs/flags)] - [:aside#settings-bar.settings-bar - [:div.settings-bar-inside - (when (contains? flags :drawtools) - (draw-toolbox)) - (when (contains? flags :element-options) - (options-toolbox)) - (when (contains? flags :icons) - (icons-toolbox))]])) + {:mixins [mx/static]} + [flags page-id] + [:aside#settings-bar.settings-bar + [:div.settings-bar-inside + (when (contains? flags :drawtools) + (draw-toolbox flags)) + (when (contains? flags :element-options) + (options-toolbox)) + (when (contains? flags :icons) + (icons-toolbox))]]) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs index 1831163ed..507081fe7 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs @@ -94,9 +94,8 @@ (mx/defc draw-toolbox {:mixins [mx/static mx/reactive]} - [] + [flags] (let [drawing-tool (mx/react refs/selected-drawing-tool) - flags (mx/react refs/flags) close #(st/emit! (udw/toggle-flag :drawtools)) tools (->> (into [] +draw-tools+) (sort-by (comp :priority second))) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/history.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/history.cljs index bd38d1ddb..d6acbb884 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/history.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/history.cljs @@ -6,28 +6,19 @@ ;; Copyright (c) 2015-2017 Juan de la Cruz (ns uxbox.main.ui.workspace.sidebar.history - (:require [lentes.core :as l] - [potok.core :as ptk] - [uxbox.main.store :as st] + (:require [uxbox.builtins.icons :as i] [uxbox.main.refs :as refs] - [uxbox.main.data.workspace :as dw] - [uxbox.main.data.pages :as udp] + [uxbox.main.store :as st] [uxbox.main.data.history :as udh] - [uxbox.builtins.icons :as i] - [uxbox.util.i18n :refer (tr)] - [uxbox.util.router :as r] - [uxbox.util.data :refer (read-string)] + [uxbox.main.data.pages :as udp] + [uxbox.main.data.workspace :as dw] + [uxbox.util.data :refer [read-string]] [uxbox.util.dom :as dom] + [uxbox.util.i18n :refer [tr]] [uxbox.util.mixins :as mx :include-macros true] + [uxbox.util.router :as r] [uxbox.util.time :as dt])) - -;; --- Lenses - -(def history-ref - (-> (l/key :history) - (l/derive refs/workspace))) - ;; --- History Item (Component) (mx/defc history-item @@ -43,69 +34,83 @@ :label "no label" :pinned (not (:pinned item)))] (st/emit! (udh/update-history-item item))))] - (let [selected? (= (:version item) selected)] - [:li {:class (when selected? "current") :on-click on-select} - [:div.pin-icon {:on-click on-pinned - :class (when (:pinned item) "selected")} - i/pin] - [:span (str "Version " (:version item) - " (" (dt/timeago (:created-at item)) ")")]]))) + [:li {:class (when (= selected (:version item)) "current") + :on-click on-select} + [:div.pin-icon {:on-click on-pinned + :class (when (:pinned item) "selected")} + i/pin] + [:span (str "Version " (:version item) + " (" (dt/timeago (:created-at item)) ")")]])) ;; --- History List (Component) (mx/defc history-list - {:mixins [mx/static]} - [page history] - (letfn [(on-select [event] - (dom/prevent-default event) - (st/emit! (udh/deselect-page-history (:id page)))) - - (on-load-more [event] - (dom/prevent-default event) - (let [since (:min-version history) - params {:since since}] - (st/emit! (udh/fetch-page-history (:id page) params))))] - - (let [selected (:selected history) - show-more? (pos? (:min-version history))] - [:ul.history-content - [:li {:class (when-not selected "current") - :on-click on-select} - [:div.pin-icon i/pin] - [:span (str "Version " (:version page) " (current)")]] - (for [version (:items history) - :let [item (get-in history [:by-version version])]] - (-> (history-item item selected) - (mx/with-key (str (:id item))))) - (if show-more? - [:li {:on-click on-load-more} - [:a.btn-primary.btn-small - "view more"]])]))) + {:mixins [mx/static mx/reactive]} + [{:keys [selected items min-version] :as history}] + (let [items (reverse (sort-by :version items)) + page (mx/react refs/selected-page) + show-more? (pos? min-version) + load-more #(st/emit! (udh/load-more))] + (println "selected" selected) + [:ul.history-content + (for [item items + :let [current? (= (:version item) (:version page))]] + (-> (history-item item selected current?) + (mx/with-key (str (:id item))))) + (when show-more? + [:li {:on-click load-more} + [:a.btn-primary.btn-small + "view more"]])])) ;; --- History Pinned List (Component) (mx/defc history-pinned-list {:mixins [mx/static]} - [history] + [{:keys [pinned selected] :as history}] [:ul.history-content - (for [version (:pinned-items history) - :let [item (get-in history [:by-version version])]] - (-> (history-item item (:selected history)) + (for [item (reverse (sort-by :version pinned)) + :let [selected? (= (:version item) selected)]] + (-> (history-item item selected?) (mx/with-key (str (:id item)))))]) ;; --- History Toolbox (Component) -(mx/defcs history-toolbox - {:mixins [mx/static mx/reactive (mx/local)]} - [{:keys [rum/local] :as own}] - (let [page (mx/react refs/selected-page) - history (mx/react refs/history) - section (:section @local :main) + +(defn- history-toolbox-will-mount + [own] + (let [[page-id] (:rum/args own)] + (st/emit! (udh/initialize page-id)) + own)) + +(defn- history-toolbox-did-remount + [oldown own] + (let [[old-page-id] (:rum/args oldown) + [new-page-id] (:rum/args own)] + (when-not (= old-page-id new-page-id) + (st/emit! ::udh/stop-changes-watcher + (udh/initialize new-page-id))) + own)) + +(defn- history-toolbox-will-unmount + [own] + (st/emit! ::udh/stop-changes-watcher) + own) + +(mx/defc history-toolbox + {:mixins [mx/static mx/reactive] + :will-mount history-toolbox-will-mount + :will-unmount history-toolbox-will-unmount + :did-remount history-toolbox-did-remount} + [_] + (let [history (mx/react refs/history) + section (:section history :main) + close #(st/emit! (dw/toggle-flag :document-history)) main? (= section :main) pinned? (= section :pinned) - show-main #(swap! local assoc :section :main) - show-pinned #(swap! local assoc :section :pinned)] + + show-main #(st/emit! (udh/select-section :main)) + show-pinned #(st/emit! (udh/select-section :pinned))] [:div.document-history.tool-window [:div.tool-window-bar [:div.tool-window-icon i/undo-history] @@ -121,17 +126,17 @@ "Pinned"]] (if (= section :pinned) (history-pinned-list history) - (history-list page history))]])) + (history-list history))]])) ;; --- History Dialog (mx/defc history-dialog {:mixins [mx/static mx/reactive]} - [page] + [] (let [history (mx/react refs/history) version (:selected history) - on-accept #(st/emit! (udh/apply-selected-history page)) - on-cancel #(st/emit! (udh/deselect-page-history page))] + on-accept #(st/emit! (udh/apply-selected-history)) + on-cancel #(st/emit! (udh/deselect-page-history))] (when (or version (:deselecting history)) [:div.message-version {:class (when (:deselecting history) "hide-message")} diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/layers.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/layers.cljs index e08d44a19..fc774dfcd 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/layers.cljs @@ -347,8 +347,6 @@ [] (let [selected (mx/react refs/selected-shapes) page (mx/react refs/selected-page) - - ;; TODO: dont react to the whole shapes-by-id shapes-map (mx/react refs/shapes-by-id) close #(st/emit! (udw/toggle-flag :layers)) dragel (volatile! nil)] diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap.cljs index 903de059d..79279e073 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap.cljs @@ -103,10 +103,9 @@ (mx/defc sitemap-toolbox {:mixins [mx/static mx/reactive]} - [] + [current] (let [project (mx/react refs/selected-project) pages (mx/react refs/selected-project-pages) - current (mx/react refs/selected-page) create #(udl/open! :page-form {:page {:project (:id project)}}) close #(st/emit! (dw/toggle-flag :sitemap))] [:div.sitemap.tool-window @@ -120,6 +119,6 @@ [:div.add-page {:on-click create} i/close]] [:ul.element-list (for [page pages - :let [active? (= (:id page) (:id current))]] + :let [active? (= (:id page) current)]] (-> (page-item page (count pages) active?) (mx/with-key (:id page))))]]])) diff --git a/frontend/src/uxbox/util/data.cljs b/frontend/src/uxbox/util/data.cljs index 69c5e8a12..0846e7a4a 100644 --- a/frontend/src/uxbox/util/data.cljs +++ b/frontend/src/uxbox/util/data.cljs @@ -57,13 +57,13 @@ coll))) (defn replace-by-id - [coll value] - {:pre [(vector? coll)]} - (mapv (fn [item] + ([value] + (map (fn [item] (if (= (:id item) (:id value)) value - item)) coll)) - + item)))) + ([coll value] + (sequence (replace-by-id value) coll))) (defn deep-merge "Like merge, but merges maps recursively." @@ -80,6 +80,16 @@ (disj s v) (conj s v))) +(defn seek + ([pred coll] + (seek pred coll nil)) + ([pred coll not-found] + (reduce (fn [_ x] + (if (pred x) + (reduced x) + not-found)) + not-found coll))) + ;; --- String utils (def +uuid-re+