🎉 Add shared libraries screen in dashboard

This commit is contained in:
Andrés Moya 2020-08-04 16:02:33 +02:00
parent 9fb821d6e0
commit 1dfab78686
8 changed files with 190 additions and 68 deletions

View file

@ -147,6 +147,32 @@
project-id profile-id]) project-id profile-id])
(mapv decode-row))) (mapv decode-row)))
;; --- Query: Shared Files
(def ^:private sql:shared-files
"select distinct
f.*,
array_agg(pg.id) over pages_w as pages,
first_value(pg.data) over pages_w as data
from file as f
left join page as pg on (f.id = pg.file_id)
where is_shared = true
and f.deleted_at is null
and pg.deleted_at is null
window pages_w as (partition by f.id order by pg.ordering
range between unbounded preceding
and unbounded following)
order by f.modified_at desc")
(s/def ::shared-files
(s/keys :req-un [::profile-id]))
(sq/defquery ::shared-files
[{:keys [profile-id] :as params}]
(->> (db/exec! db/pool [sql:shared-files])
(mapv decode-row)))
;; --- Query: File Permissions ;; --- Query: File Permissions
(def ^:private sql:file-permissions (def ^:private sql:file-permissions

View file

@ -48,19 +48,10 @@
and (ppr.is_admin = true or and (ppr.is_admin = true or
ppr.is_owner = true or ppr.is_owner = true or
ppr.can_edit = true) ppr.can_edit = true)
union
select p.*,
(select count(*) from file as f
where f.project_id = p.id
and deleted_at is null)
from project as p
where p.team_id = uuid_nil()
and p.deleted_at is null
) )
select * select *
from projects from projects
where team_id = ? where team_id = ?
or team_id = uuid_nil()
order by modified_at desc") order by modified_at desc")
(def ^:private sql:project-by-id (def ^:private sql:project-by-id

View file

@ -377,6 +377,15 @@
"es" : "Borrador" "es" : "Borrador"
} }
}, },
"dashboard.header.libraries" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/libraries.cljs:41" ],
"translations" : {
"en" : "Shared Libraries",
"fr" : "",
"ru" : "",
"es" : "Bibliotecas Compartidas"
}
},
"dashboard.header.new-file" : { "dashboard.header.new-file" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:72" ], "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:72" ],
"translations" : { "translations" : {
@ -540,7 +549,7 @@
} }
}, },
"dashboard.sidebar.drafts" : { "dashboard.sidebar.drafts" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:128" ], "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:129" ],
"translations" : { "translations" : {
"en" : "Drafts", "en" : "Drafts",
"fr" : "Brouillons", "fr" : "Brouillons",
@ -549,16 +558,16 @@
} }
}, },
"dashboard.sidebar.libraries" : { "dashboard.sidebar.libraries" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:134" ], "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:135" ],
"translations" : { "translations" : {
"en" : "Libraries", "en" : "Shared Libraries",
"fr" : "Librairies", "fr" : "",
"ru" : "Библиотеки", "ru" : "",
"es" : "Bibliotecas" "es" : "Bibliotecas Compartidas"
} }
}, },
"dashboard.sidebar.recent" : { "dashboard.sidebar.recent" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:121" ], "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:122" ],
"translations" : { "translations" : {
"en" : "Recent", "en" : "Recent",
"fr" : "Récent", "fr" : "Récent",
@ -666,7 +675,7 @@
} }
}, },
"ds.search.placeholder" : { "ds.search.placeholder" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:187" ], "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:188" ],
"translations" : { "translations" : {
"en" : "Search...", "en" : "Search...",
"fr" : "Rechercher...", "fr" : "Rechercher...",
@ -720,7 +729,7 @@
} }
}, },
"errors.generic" : { "errors.generic" : {
"used-in" : [ "src/uxbox/main/ui.cljs:201", "src/uxbox/main/ui/settings/profile.cljs:38", "src/uxbox/main/ui/auth.cljs:91" ], "used-in" : [ "src/uxbox/main/ui.cljs:204", "src/uxbox/main/ui/settings/profile.cljs:38", "src/uxbox/main/ui/auth.cljs:91" ],
"translations" : { "translations" : {
"en" : "Something wrong has happened.", "en" : "Something wrong has happened.",
"fr" : "Quelque chose c'est mal passé.", "fr" : "Quelque chose c'est mal passé.",
@ -765,7 +774,7 @@
} }
}, },
"errors.network" : { "errors.network" : {
"used-in" : [ "src/uxbox/main/ui.cljs:195" ], "used-in" : [ "src/uxbox/main/ui.cljs:198" ],
"translations" : { "translations" : {
"en" : "Unable to connect to backend server.", "en" : "Unable to connect to backend server.",
"fr" : "Impossible de se connecter au serveur principal.", "fr" : "Impossible de se connecter au serveur principal.",
@ -1071,7 +1080,7 @@
} }
}, },
"settings.notifications.email-not-verified" : { "settings.notifications.email-not-verified" : {
"used-in" : [ "src/uxbox/main/ui/dashboard.cljs:113" ], "used-in" : [ "src/uxbox/main/ui/dashboard.cljs:118" ],
"translations" : { "translations" : {
"en" : "Your email address has not been verified yet. Please check your inbox at “%s” for a confirmation email.", "en" : "Your email address has not been verified yet. Please check your inbox at “%s” for a confirmation email.",
"fr" : "Votre adresse e-mail n'a pas encore été vérifiée. Veuillez vérifier votre boîte de réception à “%s” pour un e-mail de confirmation.", "fr" : "Votre adresse e-mail n'a pas encore été vérifiée. Veuillez vérifier votre boîte de réception à “%s” pour un e-mail de confirmation.",

View file

@ -74,6 +74,7 @@
(declare fetch-files) (declare fetch-files)
(declare fetch-projects) (declare fetch-projects)
(declare fetch-recent-files) (declare fetch-recent-files)
(declare fetch-shared-files)
(def initialize-drafts (def initialize-drafts
(ptk/reify ::initialize-drafts (ptk/reify ::initialize-drafts
@ -95,7 +96,7 @@
(defn initialize-recent (defn initialize-recent
[team-id] [team-id]
(us/verify ::us/uuid team-id) (us/verify ::us/uuid team-id)
(ptk/reify ::initialize-team (ptk/reify ::initialize-recent
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(update state :dashboard-local assoc (update state :dashboard-local assoc
@ -128,6 +129,25 @@
(rx/of (fetch-projects (:team-id local) nil) (rx/of (fetch-projects (:team-id local) nil)
(fetch-files (:project-id local))))))) (fetch-files (:project-id local)))))))
(defn initialize-libraries
[team-id]
(us/verify ::us/uuid team-id)
(ptk/reify ::initialize-libraries
ptk/UpdateEvent
(update [_ state]
(update state :dashboard-local assoc
:project-for-edit nil
:project-id nil
:team-id team-id))
ptk/WatchEvent
(watch [_ state stream]
(let [local (:dashboard-local state)]
(rx/of (fetch-projects (:team-id local) nil)
(fetch-shared-files (:team-id local)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Data Fetching ;; Data Fetching
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -202,6 +222,29 @@
files (d/index-by :id files)] files (d/index-by :id files)]
(assoc state :files files))))) (assoc state :files files)))))
;; --- Fetch Shared Files
(declare shared-files-fetched)
(defn fetch-shared-files
[]
(ptk/reify ::fetch-shared-files
ptk/WatchEvent
(watch [_ state stream]
(let [params {}]
(->> (rp/query :shared-files params)
(rx/map shared-files-fetched))))))
(defn shared-files-fetched
[files]
(us/verify (s/every ::file) files)
(ptk/reify ::shared-files-fetched
ptk/UpdateEvent
(update [_ state]
(let [state (dissoc state :files)
files (d/index-by :id files)]
(assoc state :files files)))))
;; --- Fetch recent files ;; --- Fetch recent files
(declare recent-files-fetched) (declare recent-files-fetched)

View file

@ -64,20 +64,22 @@
["/" :dashboard-team] ["/" :dashboard-team]
["/search" :dashboard-search] ["/search" :dashboard-search]
["/project/:project-id" :dashboard-project] ["/project/:project-id" :dashboard-project]
["/library" ["/libraries" :dashboard-libraries]
["/icons"
["" { :name :dashboard-library-icons-index :section :icons}]
["/:library-id" { :name :dashboard-library-icons :section :icons}]]
["/images" ;; ["/library"
["" { :name :dashboard-library-images-index :section :images}] ;; ["/icons"
["/:library-id" { :name :dashboard-library-images :section :images}]] ;; ["" { :name :dashboard-library-icons-index :section :icons}]
;; ["/:library-id" { :name :dashboard-library-icons :section :icons}]]
;;
;; ["/images"
;; ["" { :name :dashboard-library-images-index :section :images}]
;; ["/:library-id" { :name :dashboard-library-images :section :images}]]
;;
;; ["/palettes"
;; ["" { :name :dashboard-library-palettes-index :section :palettes}]
;; ["/:library-id" { :name :dashboard-library-palettes :section :palettes }]]]
["/palettes" ]]
["" { :name :dashboard-library-palettes-index :section :palettes}]
["/:library-id" { :name :dashboard-library-palettes :section :palettes }]]
]]]
["/workspace/:project-id/:file-id" :workspace]]) ["/workspace/:project-id/:file-id" :workspace]])
@ -119,12 +121,13 @@
(:dashboard-search (:dashboard-search
:dashboard-team :dashboard-team
:dashboard-project :dashboard-project
:dashboard-library-icons :dashboard-libraries)
:dashboard-library-icons-index ;; :dashboard-library-icons
:dashboard-library-images ;; :dashboard-library-icons-index
:dashboard-library-images-index ;; :dashboard-library-images
:dashboard-library-palettes ;; :dashboard-library-images-index
:dashboard-library-palettes-index) ;; :dashboard-library-palettes
;; :dashboard-library-palettes-index)
[:& dashboard {:route route}] [:& dashboard {:route route}]
:viewer :viewer

View file

@ -21,7 +21,8 @@
[uxbox.main.ui.dashboard.search :refer [search-page]] [uxbox.main.ui.dashboard.search :refer [search-page]]
[uxbox.main.ui.dashboard.project :refer [project-page]] [uxbox.main.ui.dashboard.project :refer [project-page]]
[uxbox.main.ui.dashboard.recent-files :refer [recent-files-page]] [uxbox.main.ui.dashboard.recent-files :refer [recent-files-page]]
[uxbox.main.ui.dashboard.library :refer [library-page]] [uxbox.main.ui.dashboard.libraries :refer [libraries-page]]
;; [uxbox.main.ui.dashboard.library :refer [library-page]]
[uxbox.main.ui.dashboard.profile :refer [profile-section]] [uxbox.main.ui.dashboard.profile :refer [profile-section]]
[uxbox.util.router :as rt] [uxbox.util.router :as rt]
[uxbox.util.i18n :as i18n :refer [t]])) [uxbox.util.i18n :as i18n :refer [t]]))
@ -36,8 +37,8 @@
(let [search-term (get-in route [:params :query :search-term]) (let [search-term (get-in route [:params :query :search-term])
route-name (get-in route [:data :name]) route-name (get-in route [:data :name])
team-id (get-in route [:params :path :team-id]) team-id (get-in route [:params :path :team-id])
project-id (get-in route [:params :path :project-id]) project-id (get-in route [:params :path :project-id])]
library-id (get-in route [:params :path :library-id])] ;; library-id (get-in route [:params :path :library-id])]
(cond-> (cond->
{:search-term search-term} {:search-term search-term}
@ -48,13 +49,13 @@
(assoc :project-id (uuid project-id)) (assoc :project-id (uuid project-id))
(= "drafts" project-id) (= "drafts" project-id)
(assoc :project-id (:default-project-id profile)) (assoc :project-id (:default-project-id profile)))))
(str/starts-with? (name route-name) "dashboard-library") ;; (str/starts-with? (name route-name) "dashboard-library")
(assoc :library-section (get-in route [:data :section])) ;; (assoc :library-section (get-in route [:data :section]))
;;
(uuid-str? library-id) ;; (uuid-str? library-id)
(assoc :library-id (uuid library-id))))) ;; (assoc :library-id (uuid library-id)))))
(declare global-notifications) (declare global-notifications)
@ -63,7 +64,8 @@
[{:keys [route] :as props}] [{:keys [route] :as props}]
(let [profile (mf/deref refs/profile) (let [profile (mf/deref refs/profile)
page (get-in route [:data :name]) page (get-in route [:data :name])
{:keys [search-term team-id project-id library-id library-section] :as params} ;; {:keys [search-term team-id project-id library-id library-section] :as params}
{:keys [search-term team-id project-id] :as params}
(parse-params route profile)] (parse-params route profile)]
[:* [:*
[:& global-notifications {:profile profile}] [:& global-notifications {:profile profile}]
@ -84,16 +86,19 @@
:dashboard-team :dashboard-team
[:& recent-files-page {:team-id team-id}] [:& recent-files-page {:team-id team-id}]
(:dashboard-library-icons :dashboard-libraries
:dashboard-library-icons-index [:& libraries-page {:team-id team-id}]
:dashboard-library-images
:dashboard-library-images-index ;; (:dashboard-library-icons
:dashboard-library-palettes ;; :dashboard-library-icons-index
:dashboard-library-palettes-index) ;; :dashboard-library-images
[:& library-page {:key (str library-id) ;; :dashboard-library-images-index
:team-id team-id ;; :dashboard-library-palettes
:library-id library-id ;; :dashboard-library-palettes-index)
:section library-section}] ;; [:& library-page {:key (str library-id)
;; :team-id team-id
;; :library-id library-id
;; :section library-section}]
:dashboard-project :dashboard-project
[:& project-page {:team-id team-id [:& project-page {:team-id team-id

View file

@ -0,0 +1,44 @@
;; 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/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
(ns uxbox.main.ui.dashboard.libraries
(:require
[okulary.core :as l]
[rumext.alpha :as mf]
[uxbox.main.ui.icons :as i]
[uxbox.util.i18n :as i18n :refer [tr]]
[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 files-ref
(-> (comp vals :files)
(l/derived st/state)))
(mf/defc libraries-page
[{:keys [section team-id] :as props}]
(let [files (->> (mf/deref files-ref)
(sort-by :modified-at)
(reverse))]
(mf/use-effect
(mf/deps section team-id)
#(st/emit! (dsh/initialize-libraries team-id)))
[:*
[:header.main-bar
[:h1.dashboard-title (tr "dashboard.header.libraries")]]
[:section.libraries-page
[:& grid {:files files :hide-new? true}]]]))

View file

@ -104,13 +104,14 @@
selected-section selected-section
selected-project-id selected-project-id
selected-team-id] :as props}] selected-team-id] :as props}]
(let [home? (and (= selected-section :dashboard-team) (let [home? (and (= selected-section :dashboard-team)
(= selected-team-id (:default-team-id profile))) (= selected-team-id (:default-team-id profile)))
drafts? (and (= selected-section :dashboard-project) drafts? (and (= selected-section :dashboard-project)
(= selected-team-id (:default-team-id profile)) (= selected-team-id (:default-team-id profile))
(= selected-project-id (:default-project-id profile))) (= selected-project-id (:default-project-id profile)))
library? (and (str/starts-with? (name selected-section) "dashboard-library") libraries? (= selected-section :dashboard-libraries)
(= selected-team-id (:default-team-id profile))) ;; library? (and (str/starts-with? (name selected-section) "dashboard-library")
;; (= selected-team-id (:default-team-id profile)))
locale (i18n/use-locale)] locale (i18n/use-locale)]
[:div.sidebar-team [:div.sidebar-team
[:ul.library-elements.library-common [:ul.library-elements.library-common
@ -128,8 +129,8 @@
[:span.element-title (t locale "dashboard.sidebar.drafts")]] [:span.element-title (t locale "dashboard.sidebar.drafts")]]
[:li [:li
{:on-click #(st/emit! (rt/nav :dashboard-library-icons-index {:team-id team-id})) {:on-click #(st/emit! (rt/nav :dashboard-libraries {:team-id team-id}))
:class-name (when library? "current")} :class-name (when libraries? "current")}
i/icon-set i/icon-set
[:span.element-title (t locale "dashboard.sidebar.libraries")]]] [:span.element-title (t locale "dashboard.sidebar.libraries")]]]