diff --git a/backend/src/uxbox/services/queries/project_files.clj b/backend/src/uxbox/services/queries/project_files.clj index 5666e54fa..e09c13b55 100644 --- a/backend/src/uxbox/services/queries/project_files.clj +++ b/backend/src/uxbox/services/queries/project_files.clj @@ -7,9 +7,11 @@ (ns uxbox.services.queries.project-files (:require [clojure.spec.alpha :as s] + [cuerdas.core :as str] [promesa.core :as p] [uxbox.db :as db] [uxbox.services.queries :as sq] + [uxbox.services.util :as su] [uxbox.util.blob :as blob] [uxbox.util.spec :as us])) @@ -22,7 +24,7 @@ (s/def ::project-id ::us/uuid) (s/def ::user ::us/uuid) -(def ^:private sql:generic-project-files +(su/defsql sql:generic-project-files "select pf.*, array_agg(pp.id) as pages from project_files as pf @@ -31,21 +33,42 @@ left join project_pages as pp on (pf.id = pp.file_id) where pu.user_id = $1 and pu.can_edit = true - group by pf.id - order by pf.created_at asc") + group by pf.id") ;; --- Query: Project Files -(def ^:private sql:project-files - (str "with files as (" sql:generic-project-files ")" - " select * from files where project_id = $2")) +(declare retrieve-recent-files) +(declare retrieve-project-files) (s/def ::project-files - (s/keys :req-un [::user ::project-id])) + (s/keys :req-un [::user] + :opt-un [::project-id])) (sq/defquery ::project-files - [{:keys [user project-id] :as params}] - (-> (db/query db/pool [sql:project-files user project-id]) + [{:keys [project-id] :as params}] + (if (nil? project-id) + (retrieve-recent-files db/pool params) + (retrieve-project-files db/pool params))) + +(def ^:private sql:project-files + (str "with files as (" sql:generic-project-files ")" + " select * from files where project_id = $2" + " order by created_at asc")) + +(defn retrieve-project-files + [conn {:keys [user project-id]}] + (-> (db/query conn [sql:project-files user project-id]) + (p/then' (partial mapv decode-row)))) + +(su/defsql sql:recent-files + "with files as (~{sql:generic-project-files}) + select * from files + order by modified_at desc + limit $2") + +(defn retrieve-recent-files + [conn {:keys [user]}] + (-> (db/query conn [sql:recent-files user 20]) (p/then' (partial mapv decode-row)))) ;; --- Query: Project File (By ID) diff --git a/backend/src/uxbox/services/queries/projects.clj b/backend/src/uxbox/services/queries/projects.clj index 392b227ed..0e189524f 100644 --- a/backend/src/uxbox/services/queries/projects.clj +++ b/backend/src/uxbox/services/queries/projects.clj @@ -10,6 +10,7 @@ [promesa.core :as p] [uxbox.db :as db] [uxbox.services.queries :as sq] + [uxbox.services.util :as su] [uxbox.util.blob :as blob] [uxbox.util.spec :as us])) @@ -24,33 +25,20 @@ ;; --- Query: Projects -;; (def ^:private projects-sql -;; "select distinct on (p.id, p.created_at) -;; p.*, -;; array_agg(pg.id) over ( -;; partition by p.id -;; order by pg.created_at -;; range between unbounded preceding and unbounded following -;; ) as pages -;; from projects as p -;; left join pages as pg -;; on (pg.project_id = p.id) -;; where p.user_id = $1 -;; order by p.created_at asc") - -(def ^:private projects-sql +(su/defsql sql:projects "select p.* from project_users as pu inner join projects as p on (p.id = pu.project_id) where pu.can_edit = true - and pu.user_id = $1;") + and pu.user_id = $1 + order by p.created_at asc") (s/def ::projects (s/keys :req-un [::user])) (sq/defquery ::projects [{:keys [user] :as params}] - (-> (db/query db/pool [projects-sql user]) + (-> (db/query db/pool [sql:projects user]) (p/then' (partial mapv decode-row)))) ;; --- Helpers diff --git a/backend/src/uxbox/services/util.clj b/backend/src/uxbox/services/util.clj index d87fd0007..7d301fc21 100644 --- a/backend/src/uxbox/services/util.clj +++ b/backend/src/uxbox/services/util.clj @@ -7,6 +7,7 @@ (ns uxbox.services.util (:require [clojure.tools.logging :as log] + [cuerdas.core :as str] [vertx.core :as vc] [uxbox.core :refer [system]] [uxbox.util.uuid :as uuid] @@ -24,6 +25,10 @@ ;; (log/info "service" type "processed in" elapsed) ;; data))}) +(defmacro defsql + [sym str] + `(def ~sym (str/istr ~str))) + (defn raise-not-found-if-nil [v] (if (nil? v) diff --git a/frontend/src/uxbox/main/data/auth.cljs b/frontend/src/uxbox/main/data/auth.cljs index 2a684597b..1433eb69c 100644 --- a/frontend/src/uxbox/main/data/auth.cljs +++ b/frontend/src/uxbox/main/data/auth.cljs @@ -36,7 +36,7 @@ (watch [this state s] (swap! storage assoc :auth data) (rx/of du/fetch-profile - (rt/navigate :dashboard/projects))))) + (rt/navigate :dashboard-projects))))) (defn logged-in? [v] diff --git a/frontend/src/uxbox/main/data/projects.cljs b/frontend/src/uxbox/main/data/projects.cljs index 093b6d3f8..7e96271f1 100644 --- a/frontend/src/uxbox/main/data/projects.cljs +++ b/frontend/src/uxbox/main/data/projects.cljs @@ -122,8 +122,9 @@ (ptk/reify ::fetch-files ptk/WatchEvent (watch [_ state stream] - (->> (rp/query :project-files {:project-id project-id}) - (rx/map files-fetched))))) + (let [params (if (nil? project-id) {} {:project-id project-id})] + (->> (rp/query :project-files params) + (rx/map files-fetched)))))) ;; --- Fetch File (by ID) @@ -247,3 +248,13 @@ (let [path-params {:file-id file-id} query-params {:page-id (first page-ids)}] (rx/of (rt/nav :workspace path-params query-params))))))) + +(defn go-to-project + [id] + (s/assert (s/nilable ::us/uuid) id) + (ptk/reify ::go-to-project + ptk/WatchEvent + (watch [_ state stream] + (if (nil? id) + (rx/of (rt/nav :dashboard-projects {} {})) + (rx/of (rt/nav :dashboard-projects {} {:project-id (str id)})))))) diff --git a/frontend/src/uxbox/main/ui/dashboard/projects.cljs b/frontend/src/uxbox/main/ui/dashboard/projects.cljs index 23b9ad6b0..3a0c97e7a 100644 --- a/frontend/src/uxbox/main/ui/dashboard/projects.cljs +++ b/frontend/src/uxbox/main/ui/dashboard/projects.cljs @@ -30,6 +30,7 @@ (def +ordering-options+ {:name "ds.ordering.by-name" + :modified "ds.ordering.by-last-update" :created "ds.ordering.by-creation-date"}) ;; --- Refs @@ -49,6 +50,7 @@ (case ordering :name (cljs.core/sort-by :name files) :created (reverse (cljs.core/sort-by :created-at files)) + :modified (reverse (cljs.core/sort-by :modified-at files)) files)) (defn contains-term? @@ -65,8 +67,8 @@ ;; --- Menu (Filter & Sort) (mf/defc menu - [{:keys [opts files] :as props}] - (let [ordering (:order opts :created) + [{:keys [id opts files] :as props}] + (let [ordering (:order opts :modified) filtering (:filter opts "") on-term-change @@ -94,12 +96,14 @@ [:div ;; Sorting ;; TODO: convert to separate component? - [:span (tr "ds.ordering")] - [:select.input-select {:on-change on-order-change - :value (pr-str ordering)} - (for [[key value] (seq +ordering-options+)] - (let [key (pr-str key)] - [:option {:key key :value key} (tr value)]))]] + (when id + [:* + [:span (tr "ds.ordering")] + [:select.input-select {:on-change on-order-change + :value (pr-str ordering)} + (for [[key value] (seq +ordering-options+)] + (let [key (pr-str key)] + [:option {:key key :value key} (tr value)]))]])] ;; Search ;; TODO: convert to separate component? @@ -174,7 +178,7 @@ (mf/defc grid [{:keys [opts files] :as props}] - (let [order (:order opts :created) + (let [order (:order opts :modified) filter (:filter opts "") files (->> files (filter-by filter) @@ -217,8 +221,7 @@ [{:keys [id name selected?] :as props}] (let [local (mf/use-state {}) editable? (not (nil? id)) - on-click (fn [event] - (st/emit! (rt/nav :dashboard-projects {} {:project-id (str id)})))] + on-click #(st/emit! (udp/go-to-project id))] [:li {:on-click on-click ;; :on-double-click on-double-click :class-name (when selected? "current")} @@ -248,7 +251,7 @@ "new project +"]] [:li {:style {:marginBottom "20px"} - :on-click #(st/emit! (rt/nav :dashboard/projects {} {})) + :on-click #(st/emit! (udp/go-to-project nil)) :class-name (when (nil? id) "current")} [:span.element-title "Recent"]] @@ -273,7 +276,7 @@ (let [opts (mf/deref opts-iref) files (mf/deref files-ref)] [:* - [:& menu {:opts opts :files files}] + [:& menu {:id id :opts opts :files files}] [:section.dashboard-grid.library [:& grid {:id id :opts opts :files files}]]]))