Project and files edition and deletion

This commit is contained in:
Andrés Moya 2020-03-19 16:22:28 +01:00 committed by Andrey Antukh
parent 8b0eab5e90
commit b210e84dd3
9 changed files with 143 additions and 63 deletions

View file

@ -88,7 +88,7 @@
(watch [_ state stream]
(let [local (:dashboard-local state)]
(rx/of (fetch-files (:project-id local))
(fetch-projects (:team-id local) (:project-id local)))))))
(fetch-projects (:team-id local)))))))
(defn initialize-recent
@ -104,7 +104,7 @@
ptk/WatchEvent
(watch [_ state stream]
(let [local (:dashboard-local state)]
(rx/of (fetch-projects (:team-id local) (:project-id nil))
(rx/of (fetch-projects (:team-id local))
(fetch-recent-files (:team-id local)))))))
@ -122,7 +122,7 @@
ptk/WatchEvent
(watch [_ state stream]
(let [local (:dashboard-local state)]
(rx/of (fetch-projects (:team-id local) (:project-id local))
(rx/of (fetch-projects (:team-id local))
(fetch-files (:project-id local)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -141,21 +141,15 @@
ptk/WatchEvent
(watch [_ state stream]
(->> (rp/query :projects-by-team {:team-id team-id})
(rx/map (projects-fetched project-id))))))
(rx/map projects-fetched)))))
(defn projects-fetched
[project-id]
(us/assert (s/nilable ::us/uuid) project-id)
(fn [projects]
(us/verify (s/every ::project) projects)
(ptk/reify ::projects-fetched
ptk/UpdateEvent
(update [_ state]
(let [find-project #(first (filter (fn [p] (= (:id p) %1)) projects))
set-project #(assoc %1 :project (find-project project-id))
assoc-project #(assoc-in %1 [:projects (:id %2)] %2)
reduce-projects #(reduce assoc-project %1 projects)]
(-> state set-project reduce-projects))))))
[projects]
(us/verify (s/every ::project) projects)
(ptk/reify ::projects-fetched
ptk/UpdateEvent
(update [_ state]
(assoc state :projects (d/index-by :id projects)))))
;; --- Search Files
@ -221,7 +215,17 @@
(ptk/reify ::recent-files-fetched
ptk/UpdateEvent
(update [_ state]
(assoc state :recent-files recent-files))))
(let [flatten-files #(reduce (fn [acc [project-id files]]
(merge acc (d/index-by :id files)))
{}
%1)
extract-ids #(reduce (fn [acc [project-id files]]
(assoc acc project-id (map :id files)))
{}
%1)]
(assoc state
:files (flatten-files recent-files)
:recent-file-ids (extract-ids recent-files))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Data Modification
@ -229,6 +233,8 @@
;; --- Create Project
(declare project-created)
(def create-project
(ptk/reify ::create-project
ptk/WatchEvent
@ -236,8 +242,15 @@
(let [name (str "New Project " (gensym "p"))
team-id (get-in state [:dashboard-local :team-id])]
(->> (rp/mutation! :create-project {:name name :team-id team-id})
(rx/map (fn [data]
(projects-fetched [data]))))))))
(rx/map project-created))))))
(defn project-created
[data]
(us/verify ::project data)
(ptk/reify ::project-created
ptk/UpdateEvent
(update [this state]
(update state :projects assoc (:id data) data))))
;; --- Rename Project
@ -285,7 +298,7 @@
(->> (rp/mutation :delete-file {:id id})
(rx/ignore)))))
;; --- Rename Project
;; --- Rename File
(defn rename-file
[id name]
@ -299,11 +312,8 @@
(watch [_ state stream]
(let [local (:dashboard-local state)
params {:id id :name name}]
;; NOTE: this is a temporal (quick & dirty) solution for
;; refreshing the results; we need to think in a better way to
;; do it instead of a simple and complete data refresh.
(->> (rp/mutation :rename-file params)
(rx/map (fn [_] (initialize-recent (:team-id local)))))))))
(rx/ignore))))))
;; --- Create File
@ -312,7 +322,7 @@
(defn create-file
[project-id]
(ptk/reify ::create-draft-file
(ptk/reify ::create-file
ptk/WatchEvent
(watch [_ state stream]
(let [name (str "New File " (gensym "p"))
@ -323,12 +333,10 @@
(defn file-created
[data]
(us/verify ::file data)
(ptk/reify ::create-draft-file
(ptk/reify ::file-created
ptk/UpdateEvent
(update [this state]
(-> state
(update :files assoc (:id data) data)
(update-in [:recent-files (:project-id data)] conj data)))))
(update state :files assoc (:id data) data))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -11,6 +11,7 @@
[uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.confirm :refer [confirm-dialog]]
[uxbox.main.ui.components.context-menu :refer [context-menu]]
[uxbox.util.data :refer [classnames]]
[uxbox.util.dom :as dom]
[uxbox.util.i18n :as i18n :refer [t tr]]
[uxbox.util.router :as rt]
@ -51,7 +52,9 @@
(st/emit! (dsh/rename-file (:id file) name))
(swap! local assoc :edition false))
on-key-down #(when (kbd/enter? %) (on-blur %))
on-key-down #(cond
(kbd/enter? %) (on-blur %)
(kbd/esc? %) (swap! local assoc :edition false))
on-menu-click #(do
(dom/stop-propagation %)
(swap! local assoc :menu-open true))
@ -68,11 +71,11 @@
:auto-focus true
:on-key-down on-key-down
:on-blur on-blur
;; :on-click on-edit
:default-value (:name file)}]
[:h3 (:name file)])
[:& grid-item-metadata {:modified-at (:modified-at file)}]]
[:div.project-th-actions
[:div.project-th-actions {:class (classnames
:force-display (:menu-open @local))}
;; [:div.project-th-icon.pages
;; i/page
;; #_[:span (:total-pages project)]]

View file

@ -12,14 +12,20 @@
(:require
[lentes.core :as l]
[rumext.alpha :as mf]
[uxbox.builtins.icons :as i]
[uxbox.util.i18n :as i18n :refer [t]]
[uxbox.util.dom :as dom]
[uxbox.util.router :as rt]
[uxbox.main.data.dashboard :as dsh]
[uxbox.main.store :as st]
[uxbox.main.ui.modal :as modal]
[uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.confirm :refer [confirm-dialog]]
[uxbox.main.ui.components.context-menu :refer [context-menu]]
[uxbox.main.ui.dashboard.grid :refer [grid]]))
(def project-ref
(-> (l/key :project)
(def projects-ref
(-> (l/key :projects)
(l/derive st/state)))
(def files-ref
@ -28,16 +34,47 @@
(l/derive st/state)))
(mf/defc project-header
[{:keys [profile] :as props}]
(let [project (mf/deref project-ref)
locale (i18n/use-locale)]
[{:keys [team-id project-id] :as props}]
(let [local (mf/use-state {:menu-open false
:edition false})
projects (mf/deref projects-ref)
project (get projects project-id)
locale (i18n/use-locale)
on-menu-click #(swap! local assoc :menu-open true)
on-menu-close #(swap! local assoc :menu-open false)
on-edit #(swap! local assoc :edition true :menu-open false)
on-blur #(let [name (-> % dom/get-target dom/get-value)]
(st/emit! (dsh/rename-project project-id name))
(swap! local assoc :edition false))
on-key-down #(cond
(kbd/enter? %) (on-blur %)
(kbd/esc? %) (swap! local assoc :edition false))
delete-fn #(do
(st/emit! (dsh/delete-project project-id))
(st/emit! (rt/nav :dashboard-team {:team-id team-id})))
on-delete #(modal/show! confirm-dialog {:on-accept delete-fn})]
[:header#main-bar.main-bar
(if (:is-default project)
[:h1.dashboard-title (t locale "dashboard.header.draft")]
[:h1.dashboard-title (t locale "dashboard.header.project" (:name project))])
[:*
(if (:edition @local)
[:input.element-name {:type "text"
:auto-focus true
:on-key-down on-key-down
:on-blur on-blur
:default-value (:name project)}]
[:h1.dashboard-title
[:div.main-bar-icon
{:on-click on-menu-click}
i/actions]
[:& context-menu {:on-close on-menu-close
:show (:menu-open @local)
:options [[(t locale "dashboard.grid.edit") on-edit]
[(t locale "dashboard.grid.delete") on-delete]]}]
(t locale "dashboard.header.project" (:name project))])])
[:a.btn-dashboard {:on-click #(do
(dom/prevent-default %)
(st/emit! (dsh/create-file (:id project))))}
(st/emit! (dsh/create-file project-id)))}
(t locale "dashboard.header.new-file")]]))
(mf/defc project-page
@ -47,10 +84,10 @@
(reverse))]
(mf/use-effect
{:fn #(st/emit! (dsh/initialize-project team-id project-id))
:deps (mf/deps team-id project-id)})
:deps (mf/deps section team-id project-id)})
[:*
[:& project-header]
[:& project-header {:team-id team-id :project-id project-id}]
[:section.projects-page
[:& grid { :id project-id :files files :hide-new? true}]]]))

View file

@ -35,8 +35,12 @@
(-> (l/key :projects)
(l/derive st/state)))
(def recent-files-ref
(-> (l/key :recent-files)
(def recent-file-ids-ref
(-> (l/key :recent-file-ids)
(l/derive st/state)))
(def files-ref
(-> (l/key :files)
(l/derive st/state)))
;; --- Component: Recent files
@ -46,7 +50,8 @@
(let [locale (i18n/use-locale)]
[:header#main-bar.main-bar
[:h1.dashboard-title "Recent"]
[:a.btn-dashboard "+ New project"]]))
[:a.btn-dashboard {:on-click #(st/emit! dsh/create-project)}
(t locale "dashboard.header.new-project")]]))
(mf/defc recent-project
[{:keys [project files first? locale] :as props}]
@ -60,12 +65,12 @@
(dt/timeago {:locale locale}))]
[:span.recent-files-row-title-info (str ", " time)])]
[:& grid {:id (:id project)
:files (or files [])
:files files
:hide-new? true}]]))
(mf/defc recent-files-page
[{:keys [section team-id] :as props}]
[{:keys [team-id] :as props}]
(mf/use-effect
{:fn #(st/emit! (dsh/initialize-recent team-id))
:deps (mf/deps team-id)})
@ -73,10 +78,11 @@
(vals)
(sort-by :modified-at)
(reverse))
recent-files (mf/deref recent-files-ref)
files (mf/deref files-ref)
recent-file-ids (mf/deref recent-file-ids-ref)
locale (i18n/use-locale)]
(when (and projects recent-files)
(when (and projects recent-file-ids)
[:*
[:& recent-files-header]
[:section.recent-files-page
@ -84,6 +90,8 @@
[:& recent-project {:project project
:locale locale
:key (:id project)
:files (get recent-files (:id project))
:files (->> (get recent-file-ids (:id project))
(map #(get files %))
(filter identity)) ;; avoid failure if a "project only" files list is in global state
:first? (= project (first projects))}])]])))