mirror of
https://github.com/penpot/penpot.git
synced 2025-05-28 22:56:11 +02:00
Project and files edition and deletion
This commit is contained in:
parent
8b0eab5e90
commit
b210e84dd3
9 changed files with 143 additions and 63 deletions
|
@ -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))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -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)]]
|
||||
|
|
|
@ -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}]]]))
|
||||
|
||||
|
|
|
@ -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))}])]])))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue