From 1dfab78686dc767d4cc0042dc6ab371a92ecc96e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Tue, 4 Aug 2020 16:02:33 +0200 Subject: [PATCH] :tada: Add shared libraries screen in dashboard --- backend/src/uxbox/services/queries/files.clj | 26 +++++++++++ .../src/uxbox/services/queries/projects.clj | 9 ---- frontend/resources/locales.json | 31 ++++++++----- frontend/src/uxbox/main/data/dashboard.cljs | 45 ++++++++++++++++++- frontend/src/uxbox/main/ui.cljs | 39 ++++++++-------- frontend/src/uxbox/main/ui/dashboard.cljs | 45 ++++++++++--------- .../uxbox/main/ui/dashboard/libraries.cljs | 44 ++++++++++++++++++ .../src/uxbox/main/ui/dashboard/sidebar.cljs | 19 ++++---- 8 files changed, 190 insertions(+), 68 deletions(-) create mode 100644 frontend/src/uxbox/main/ui/dashboard/libraries.cljs diff --git a/backend/src/uxbox/services/queries/files.clj b/backend/src/uxbox/services/queries/files.clj index 3991dc4c6..e107e1b9d 100644 --- a/backend/src/uxbox/services/queries/files.clj +++ b/backend/src/uxbox/services/queries/files.clj @@ -147,6 +147,32 @@ project-id profile-id]) (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 (def ^:private sql:file-permissions diff --git a/backend/src/uxbox/services/queries/projects.clj b/backend/src/uxbox/services/queries/projects.clj index d7b254cde..6636c4b92 100644 --- a/backend/src/uxbox/services/queries/projects.clj +++ b/backend/src/uxbox/services/queries/projects.clj @@ -48,19 +48,10 @@ and (ppr.is_admin = true or ppr.is_owner = true or 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 * from projects where team_id = ? - or team_id = uuid_nil() order by modified_at desc") (def ^:private sql:project-by-id diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json index 39f194fe1..895ae0439 100644 --- a/frontend/resources/locales.json +++ b/frontend/resources/locales.json @@ -377,6 +377,15 @@ "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" : { "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:72" ], "translations" : { @@ -540,7 +549,7 @@ } }, "dashboard.sidebar.drafts" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:128" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:129" ], "translations" : { "en" : "Drafts", "fr" : "Brouillons", @@ -549,16 +558,16 @@ } }, "dashboard.sidebar.libraries" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:134" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:135" ], "translations" : { - "en" : "Libraries", - "fr" : "Librairies", - "ru" : "Библиотеки", - "es" : "Bibliotecas" + "en" : "Shared Libraries", + "fr" : "", + "ru" : "", + "es" : "Bibliotecas Compartidas" } }, "dashboard.sidebar.recent" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:121" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:122" ], "translations" : { "en" : "Recent", "fr" : "Récent", @@ -666,7 +675,7 @@ } }, "ds.search.placeholder" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:187" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:188" ], "translations" : { "en" : "Search...", "fr" : "Rechercher...", @@ -720,7 +729,7 @@ } }, "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" : { "en" : "Something wrong has happened.", "fr" : "Quelque chose c'est mal passé.", @@ -765,7 +774,7 @@ } }, "errors.network" : { - "used-in" : [ "src/uxbox/main/ui.cljs:195" ], + "used-in" : [ "src/uxbox/main/ui.cljs:198" ], "translations" : { "en" : "Unable to connect to backend server.", "fr" : "Impossible de se connecter au serveur principal.", @@ -1071,7 +1080,7 @@ } }, "settings.notifications.email-not-verified" : { - "used-in" : [ "src/uxbox/main/ui/dashboard.cljs:113" ], + "used-in" : [ "src/uxbox/main/ui/dashboard.cljs:118" ], "translations" : { "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.", diff --git a/frontend/src/uxbox/main/data/dashboard.cljs b/frontend/src/uxbox/main/data/dashboard.cljs index 4a281d8e0..183bc5aba 100644 --- a/frontend/src/uxbox/main/data/dashboard.cljs +++ b/frontend/src/uxbox/main/data/dashboard.cljs @@ -74,6 +74,7 @@ (declare fetch-files) (declare fetch-projects) (declare fetch-recent-files) +(declare fetch-shared-files) (def initialize-drafts (ptk/reify ::initialize-drafts @@ -95,7 +96,7 @@ (defn initialize-recent [team-id] (us/verify ::us/uuid team-id) - (ptk/reify ::initialize-team + (ptk/reify ::initialize-recent ptk/UpdateEvent (update [_ state] (update state :dashboard-local assoc @@ -128,6 +129,25 @@ (rx/of (fetch-projects (:team-id local) nil) (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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -202,6 +222,29 @@ files (d/index-by :id 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 (declare recent-files-fetched) diff --git a/frontend/src/uxbox/main/ui.cljs b/frontend/src/uxbox/main/ui.cljs index 574d08c85..0a4d0c08d 100644 --- a/frontend/src/uxbox/main/ui.cljs +++ b/frontend/src/uxbox/main/ui.cljs @@ -64,20 +64,22 @@ ["/" :dashboard-team] ["/search" :dashboard-search] ["/project/:project-id" :dashboard-project] - ["/library" - ["/icons" - ["" { :name :dashboard-library-icons-index :section :icons}] - ["/:library-id" { :name :dashboard-library-icons :section :icons}]] + ["/libraries" :dashboard-libraries] - ["/images" - ["" { :name :dashboard-library-images-index :section :images}] - ["/:library-id" { :name :dashboard-library-images :section :images}]] + ;; ["/library" + ;; ["/icons" + ;; ["" { :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]]) @@ -119,12 +121,13 @@ (:dashboard-search :dashboard-team :dashboard-project - :dashboard-library-icons - :dashboard-library-icons-index - :dashboard-library-images - :dashboard-library-images-index - :dashboard-library-palettes - :dashboard-library-palettes-index) + :dashboard-libraries) + ;; :dashboard-library-icons + ;; :dashboard-library-icons-index + ;; :dashboard-library-images + ;; :dashboard-library-images-index + ;; :dashboard-library-palettes + ;; :dashboard-library-palettes-index) [:& dashboard {:route route}] :viewer diff --git a/frontend/src/uxbox/main/ui/dashboard.cljs b/frontend/src/uxbox/main/ui/dashboard.cljs index c7d234227..c7fceaa54 100644 --- a/frontend/src/uxbox/main/ui/dashboard.cljs +++ b/frontend/src/uxbox/main/ui/dashboard.cljs @@ -21,7 +21,8 @@ [uxbox.main.ui.dashboard.search :refer [search-page]] [uxbox.main.ui.dashboard.project :refer [project-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.util.router :as rt] [uxbox.util.i18n :as i18n :refer [t]])) @@ -36,8 +37,8 @@ (let [search-term (get-in route [:params :query :search-term]) route-name (get-in route [:data :name]) team-id (get-in route [:params :path :team-id]) - project-id (get-in route [:params :path :project-id]) - library-id (get-in route [:params :path :library-id])] + project-id (get-in route [:params :path :project-id])] + ;; library-id (get-in route [:params :path :library-id])] (cond-> {:search-term search-term} @@ -48,13 +49,13 @@ (assoc :project-id (uuid 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") - (assoc :library-section (get-in route [:data :section])) - - (uuid-str? library-id) - (assoc :library-id (uuid library-id))))) + ;; (str/starts-with? (name route-name) "dashboard-library") + ;; (assoc :library-section (get-in route [:data :section])) + ;; + ;; (uuid-str? library-id) + ;; (assoc :library-id (uuid library-id))))) (declare global-notifications) @@ -63,7 +64,8 @@ [{:keys [route] :as props}] (let [profile (mf/deref refs/profile) 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)] [:* [:& global-notifications {:profile profile}] @@ -84,16 +86,19 @@ :dashboard-team [:& recent-files-page {:team-id team-id}] - (:dashboard-library-icons - :dashboard-library-icons-index - :dashboard-library-images - :dashboard-library-images-index - :dashboard-library-palettes - :dashboard-library-palettes-index) - [:& library-page {:key (str library-id) - :team-id team-id - :library-id library-id - :section library-section}] + :dashboard-libraries + [:& libraries-page {:team-id team-id}] + + ;; (:dashboard-library-icons + ;; :dashboard-library-icons-index + ;; :dashboard-library-images + ;; :dashboard-library-images-index + ;; :dashboard-library-palettes + ;; :dashboard-library-palettes-index) + ;; [:& library-page {:key (str library-id) + ;; :team-id team-id + ;; :library-id library-id + ;; :section library-section}] :dashboard-project [:& project-page {:team-id team-id diff --git a/frontend/src/uxbox/main/ui/dashboard/libraries.cljs b/frontend/src/uxbox/main/ui/dashboard/libraries.cljs new file mode 100644 index 000000000..179aacb5c --- /dev/null +++ b/frontend/src/uxbox/main/ui/dashboard/libraries.cljs @@ -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}]]])) + diff --git a/frontend/src/uxbox/main/ui/dashboard/sidebar.cljs b/frontend/src/uxbox/main/ui/dashboard/sidebar.cljs index c49b061c6..3e7f0b6fe 100644 --- a/frontend/src/uxbox/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/uxbox/main/ui/dashboard/sidebar.cljs @@ -104,13 +104,14 @@ selected-section selected-project-id selected-team-id] :as props}] - (let [home? (and (= selected-section :dashboard-team) - (= selected-team-id (:default-team-id profile))) - drafts? (and (= selected-section :dashboard-project) - (= selected-team-id (:default-team-id profile)) - (= selected-project-id (:default-project-id profile))) - library? (and (str/starts-with? (name selected-section) "dashboard-library") - (= selected-team-id (:default-team-id profile))) + (let [home? (and (= selected-section :dashboard-team) + (= selected-team-id (:default-team-id profile))) + drafts? (and (= selected-section :dashboard-project) + (= selected-team-id (:default-team-id profile)) + (= selected-project-id (:default-project-id profile))) + libraries? (= selected-section :dashboard-libraries) + ;; library? (and (str/starts-with? (name selected-section) "dashboard-library") + ;; (= selected-team-id (:default-team-id profile))) locale (i18n/use-locale)] [:div.sidebar-team [:ul.library-elements.library-common @@ -128,8 +129,8 @@ [:span.element-title (t locale "dashboard.sidebar.drafts")]] [:li - {:on-click #(st/emit! (rt/nav :dashboard-library-icons-index {:team-id team-id})) - :class-name (when library? "current")} + {:on-click #(st/emit! (rt/nav :dashboard-libraries {:team-id team-id})) + :class-name (when libraries? "current")} i/icon-set [:span.element-title (t locale "dashboard.sidebar.libraries")]]]