diff --git a/frontend/src/app/main.cljs b/frontend/src/app/main.cljs index e80e545f8..dc2a58f96 100644 --- a/frontend/src/app/main.cljs +++ b/frontend/src/app/main.cljs @@ -9,7 +9,7 @@ [app.common.spec :as us] [app.common.uuid :as uuid] [app.config :as cfg] - [app.main.data.auth :as da] + [app.main.data.events :as ev] [app.main.data.messages :as dm] [app.main.data.users :as du] [app.main.repo :as rp] @@ -28,6 +28,7 @@ [app.util.timers :as ts] [beicon.core :as rx] [cljs.spec.alpha :as s] + [potok.core :as ptk] [rumext.alpha :as mf])) (log/initialize!) @@ -52,18 +53,16 @@ (defn on-navigate [router path] (let [match (match-path router path) - profile (:profile storage) + profile (:profile @storage) nopath? (or (= path "") (= path "/")) authed? (and (not (nil? profile)) (not= (:id profile) uuid/zero))] (cond (and nopath? authed? (nil? match)) - (->> (rp/query! :profile) - (rx/subs (fn [profile] - (if (not= uuid/zero profile) - (st/emit! (rt/nav :dashboard-projects {:team-id (da/current-team-id profile)})) - (st/emit! (rt/nav :auth-login)))))) + (if (not= uuid/zero profile) + (st/emit! (rt/nav :dashboard-projects {:team-id (du/get-current-team-id profile)})) + (st/emit! (rt/nav :auth-login))) (and (not authed?) (nil? match)) (st/emit! (rt/nav :auth-login)) @@ -72,23 +71,42 @@ (st/emit! (dm/assign-exception {:type :not-found})) :else - (st/emit! #(assoc % :route match))))) + (st/emit! (rt/navigated match))))) (defn init-ui [] (mf/mount (mf/element ui/app) (dom/get-element "app")) (mf/mount (mf/element modal) (dom/get-element "modal"))) + +(defn initialize + [] + (letfn [(on-profile [profile] + (rx/of (rt/initialize-router ui/routes) + (rt/initialize-history on-navigate)))] + (ptk/reify ::initialize + ptk/UpdateEvent + (update [_ state] + (assoc state :session-id (uuid/next))) + + ptk/WatchEvent + (watch [_ state stream] + (rx/merge + (rx/of + (ptk/event ::ev/initialize) + (du/initialize-profile)) + (->> stream + (rx/filter (ptk/type? ::du/profile-fetched)) + (rx/take 1) + (rx/map deref) + (rx/mapcat on-profile))))))) + (defn ^:export init [] (i18n/init! cfg/translations) (theme/init! cfg/themes) - (st/init) (init-ui) - - (st/emit! (rt/initialize-router ui/routes) - (rt/initialize-history on-navigate) - (du/fetch-profile-and-teams))) + (st/emit! (initialize))) (defn reinit [] @@ -103,3 +121,4 @@ (defn ^:dev/after-load after-load [] (reinit)) + diff --git a/frontend/src/app/main/data/auth.cljs b/frontend/src/app/main/data/auth.cljs deleted file mode 100644 index 694ff93b9..000000000 --- a/frontend/src/app/main/data/auth.cljs +++ /dev/null @@ -1,205 +0,0 @@ -;; 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/. -;; -;; Copyright (c) UXBOX Labs SL - -(ns app.main.data.auth - (:require - [app.common.spec :as us] - [app.config :as cf] - [app.main.data.messages :as dm] - [app.main.data.modal :as modal] - [app.main.data.users :as du] - [app.main.repo :as rp] - [app.main.store :refer [initial-state]] - [app.util.i18n :as i18n :refer [tr]] - [app.util.router :as rt] - [app.util.storage :refer [storage]] - [beicon.core :as rx] - [cljs.spec.alpha :as s] - [potok.core :as ptk])) - -(s/def ::email ::us/email) -(s/def ::password string?) -(s/def ::fullname string?) - -;; --- Current team for a profile - -(defn current-team-id - [profile] - (let [team-id (:current-team-id storage)] - (or team-id (:default-team-id profile)))) - -(defn set-current-team! - [team-id] - (swap! storage assoc :current-team-id team-id)) - -;; --- Logged In - -(defn logged-in - [profile] - (ptk/reify ::logged-in - ptk/WatchEvent - (watch [this state stream] - (let [team-id (current-team-id profile) - props (:props profile)] - (rx/concat - (rx/of (du/profile-fetched profile)) - (rx/of (du/fetch-teams)) - (rx/of (rt/nav' :dashboard-projects {:team-id team-id})) - (when-not (:onboarding-viewed props) - (->> (rx/of (modal/show {:type :onboarding})) - (rx/delay 1000)))))))) - -;; --- Login - -(s/def ::login-params - (s/keys :req-un [::email ::password])) - -(defn login - [{:keys [email password] :as data}] - (us/verify ::login-params data) - (ptk/reify ::login - ptk/UpdateEvent - (update [_ state] - (merge state (dissoc initial-state :route :router))) - - ptk/WatchEvent - (watch [this state s] - (let [{:keys [on-error on-success] - :or {on-error identity - on-success identity}} (meta data) - params {:email email - :password password - :scope "webapp"}] - (->> (rx/timer 100) - (rx/mapcat #(rp/mutation :login params)) - (rx/tap on-success) - (rx/catch on-error) - (rx/map logged-in)))))) - -(defn login-from-token - [{:keys [profile] :as tdata}] - (ptk/reify ::login-from-token - ptk/UpdateEvent - (update [_ state] - (merge state (dissoc initial-state :route :router))) - - ptk/WatchEvent - (watch [this state s] - (rx/of (logged-in profile))))) - -;; --- Logout - -(def clear-user-data - (ptk/reify ::clear-user-data - ptk/UpdateEvent - (update [_ state] - (select-keys state [:route :router :session-id :history])) - - ptk/WatchEvent - (watch [_ state s] - (->> (rp/mutation :logout) - (rx/catch (constantly (rx/empty))) - (rx/ignore))) - - ptk/EffectEvent - (effect [_ state s] - (reset! storage {}) - (i18n/reset-locale)))) - -(defn logout - [] - (ptk/reify ::logout - ptk/WatchEvent - (watch [_ state stream] - (rx/of clear-user-data - (rt/nav :auth-login))))) - -;; --- Register - -(s/def ::invitation-token ::us/not-empty-string) - -(s/def ::register - (s/keys :req-un [::fullname ::password ::email] - :opt-un [::invitation-token])) - -(defn register - "Create a register event instance." - [data] - (s/assert ::register data) - (ptk/reify ::register - ptk/WatchEvent - (watch [_ state stream] - (let [{:keys [on-error on-success] - :or {on-error identity - on-success identity}} (meta data)] - (->> (rp/mutation :register-profile data) - (rx/tap on-success) - (rx/catch on-error)))))) - - -;; --- Request Account Deletion - -(defn request-account-deletion - [params] - (ptk/reify ::request-account-deletion - ptk/WatchEvent - (watch [_ state stream] - (let [{:keys [on-error on-success] - :or {on-error identity - on-success identity}} (meta params)] - (->> (rp/mutation :delete-profile {}) - (rx/tap on-success) - (rx/catch on-error)))))) - -;; --- Recovery Request - -(s/def ::recovery-request - (s/keys :req-un [::email])) - -(defn request-profile-recovery - [data] - (us/verify ::recovery-request data) - (ptk/reify ::request-profile-recovery - ptk/WatchEvent - (watch [_ state stream] - (let [{:keys [on-error on-success] - :or {on-error identity - on-success identity}} (meta data)] - - (->> (rp/mutation :request-profile-recovery data) - (rx/tap on-success) - (rx/catch on-error)))))) - -;; --- Recovery (Password) - -(s/def ::token string?) -(s/def ::recover-profile - (s/keys :req-un [::password ::token])) - -(defn recover-profile - [{:keys [token password] :as data}] - (us/verify ::recover-profile data) - (ptk/reify ::recover-profile - ptk/WatchEvent - (watch [_ state stream] - (let [{:keys [on-error on-success] - :or {on-error identity - on-success identity}} (meta data)] - (->> (rp/mutation :recover-profile data) - (rx/tap on-success) - (rx/catch (fn [err] - (on-error) - (rx/empty)))))))) - - -;; --- Create Demo Profile - -(def create-demo-profile - (ptk/reify ::create-demo-profile - ptk/WatchEvent - (watch [_ state stream] - (->> (rp/mutation :create-demo-profile {}) - (rx/map login))))) diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs index a09a1f1d4..40f09051f 100644 --- a/frontend/src/app/main/data/dashboard.cljs +++ b/frontend/src/app/main/data/dashboard.cljs @@ -11,6 +11,7 @@ [app.common.spec :as us] [app.common.uuid :as uuid] [app.main.repo :as rp] + [app.main.data.events :as ev] [app.main.data.users :as du] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] @@ -242,10 +243,12 @@ (watch [_ state stream] (let [{:keys [on-success on-error] :or {on-success identity - on-error identity}} (meta params)] + on-error rx/throw}} (meta params)] (->> (rp/mutation! :create-team {:name name}) (rx/tap on-success) - (rx/catch on-error)))))) + (rx/catch on-error) + (rx/map (fn [team] + (ptk/event ::ev/event {::ev/name "create-team" :id (:id team)})))))))) (defn update-team [{:keys [id name] :as params}] @@ -316,7 +319,7 @@ (watch [_ state stream] (let [{:keys [on-success on-error] :or {on-success identity - on-error identity}} (meta params)] + on-error rx/throw}} (meta params)] (rx/concat (when (uuid? reassign-to) (->> (rp/mutation! :update-team-member-role {:team-id id @@ -337,7 +340,7 @@ (watch [_ state stream] (let [{:keys [on-success on-error] :or {on-success identity - on-error identity}} (meta params)] + on-error rx/throw}} (meta params)] (->> (rp/mutation! :invite-team-member params) (rx/tap on-success) (rx/catch on-error)))))) @@ -350,29 +353,38 @@ (watch [_ state stream] (let [{:keys [on-success on-error] :or {on-success identity - on-error identity}} (meta params)] + on-error rx/throw}} (meta params)] (->> (rp/mutation! :delete-team {:id id}) (rx/tap on-success) (rx/catch on-error)))))) + +(defn- project-created + [{:keys [id team-id] :as project}] + (ptk/reify ::project-created + IDeref + (-deref [_] project) + + ptk/UpdateEvent + (update [_ state] + (-> state + (assoc-in [:projects team-id id] project) + (assoc-in [:dashboard-local :project-for-edit] id))))) + (defn create-project [{:keys [team-id] :as params}] (us/assert ::us/uuid team-id) - (letfn [(created [project state] - (-> state - (assoc-in [:projects team-id (:id project)] project) - (assoc-in [:dashboard-local :project-for-edit] (:id project))))] - (ptk/reify ::create-project - ptk/WatchEvent - (watch [_ state stream] - (let [name (name (gensym "New Project ")) - {:keys [on-success on-error] - :or {on-success identity - on-error identity}} (meta params)] - (->> (rp/mutation! :create-project {:name name :team-id team-id}) - (rx/tap on-success) - (rx/map #(partial created %)) - (rx/catch on-error))))))) + (ptk/reify ::create-project + ptk/WatchEvent + (watch [_ state stream] + (let [name (name (gensym "New Project ")) + {:keys [on-success on-error] + :or {on-success identity + on-error rx/throw}} (meta params)] + (->> (rp/mutation! :create-project {:name name :team-id team-id}) + (rx/tap on-success) + (rx/catch on-error) + (rx/map project-created)))))) (defn duplicate-project [{:keys [id name] :as params}] @@ -532,20 +544,23 @@ (watch [_ state stream] (let [{:keys [on-success on-error] :or {on-success identity - on-error identity}} (meta params) + on-error rx/throw}} (meta params) name (name (gensym "New File ")) params (assoc params :name name)] (->> (rp/mutation! :create-file params) (rx/tap on-success) - (rx/map file-created) - (rx/catch on-error)))))) + (rx/catch on-error) + (rx/map file-created)))))) (defn file-created [{:keys [project-id id] :as file}] (us/verify ::file file) (ptk/reify ::file-created + IDeref + (-deref [_] file) + ptk/UpdateEvent (update [_ state] (-> state diff --git a/frontend/src/app/main/data/users.cljs b/frontend/src/app/main/data/users.cljs index 283a9bad9..d2f47b53b 100644 --- a/frontend/src/app/main/data/users.cljs +++ b/frontend/src/app/main/data/users.cljs @@ -10,7 +10,9 @@ [app.common.data :as d] [app.common.spec :as us] [app.common.uuid :as uuid] + [app.main.data.events :as ev] [app.main.data.media :as di] + [app.main.data.modal :as modal] [app.main.data.messages :as dm] [app.main.repo :as rp] [app.main.store :as st] @@ -24,7 +26,7 @@ [cuerdas.core :as str] [potok.core :as ptk])) -;; --- Common Specs +;; --- COMMON SPECS (s/def ::id ::us/uuid) (s/def ::fullname ::us/string) @@ -45,6 +47,20 @@ ::lang ::theme])) +;; --- HELPERS + +(defn get-current-team-id + [profile] + (let [team-id (::current-team-id @storage)] + (or team-id (:default-team-id profile)))) + +(defn set-current-team! + [team-id] + (swap! storage assoc ::current-team-id team-id)) + + +;; --- EVENT: fetch-teams + (defn fetch-teams [] (letfn [(on-fetched [state data] @@ -57,25 +73,26 @@ (rx/map (fn [data] #(on-fetched % data)))))))) (defn profile-fetched - [{:keys [fullname id] :as data}] - (us/verify ::profile data) + [{:keys [id] :as profile}] + (us/verify ::profile profile) (ptk/reify ::profile-fetched IDeref - (-deref [_] data) + (-deref [_] profile) ptk/UpdateEvent (update [_ state] (-> state (assoc :profile-id id) - (assoc :profile data))) + (assoc :profile profile))) ptk/EffectEvent (effect [_ state stream] (let [profile (:profile state)] - (swap! storage assoc :profile profile) - (i18n/set-locale! (:lang profile)) - (some-> (:theme profile) - (theme/set-current-theme!)))))) + (when (not= uuid/zero (:id profile)) + (swap! storage assoc :profile profile) + (i18n/set-locale! (:lang profile)) + (some-> (:theme profile) + (theme/set-current-theme!))))))) ;; --- Fetch Profile @@ -87,12 +104,14 @@ (->> (rp/query! :profile) (rx/map profile-fetched))))) -(defn fetch-profile-and-teams +;; --- EVENT: INITIALIZE PROFILE + +(defn initialize-profile "Event used mainly on application bootstrap; it fetches the profile and if and only if the fetched profile corresponds to an authenticated user; proceed to fetch teams." [] - (ptk/reify ::fetch-profile-and-teams + (ptk/reify ::initialize-profile ptk/WatchEvent (watch [_ state stream] (rx/merge @@ -104,7 +123,117 @@ (rx/mapcat (fn [profile] (if (= uuid/zero (:id profile)) (rx/empty) - (rx/of (fetch-teams)))))))))) + (rx/of + (fetch-teams) + (ptk/event ::ev/event + {::ev/type "identify" + ::ev/name "page-load"})))))))))) + + +;; --- EVENT: login + +(defn- logged-in + [profile] + (ptk/reify ::logged-in + IDeref + (-deref [_] profile) + + ptk/WatchEvent + (watch [this state stream] + (let [team-id (get-current-team-id profile) + profile (with-meta profile + {::ev/source "login"})] + (->> (rx/concat + (rx/of (profile-fetched profile) + (fetch-teams) + (rt/nav' :dashboard-projects {:team-id team-id})) + (when-not (get-in profile [:props :onboarding-viewed]) + (->> (rx/of (modal/show {:type :onboarding})) + (rx/delay 1000)))) + (rx/observe-on :async)))))) + +(s/def ::login-params + (s/keys :req-un [::email ::password])) + +(defn login + [{:keys [email password] :as data}] + (us/verify ::login-params data) + (ptk/reify ::login + ptk/WatchEvent + (watch [this state s] + (let [{:keys [on-error on-success] + :or {on-error rx/throw + on-success identity}} (meta data) + params {:email email + :password password + :scope "webapp"}] + (->> (rx/timer 100) + (rx/mapcat #(rp/mutation :login params)) + (rx/tap on-success) + (rx/catch on-error) + (rx/map (fn [profile] + (with-meta profile + {::ev/source "login"}))) + (rx/map logged-in)))))) + +(defn login-from-token + [{:keys [profile] :as tdata}] + (ptk/reify ::login-from-token + ptk/WatchEvent + (watch [this state s] + (rx/of (logged-in + (with-meta profile + {::ev/source "login-with-token"})))))) + +;; --- EVENT: logout + +(defn logged-out + [] + (ptk/reify ::logged-out + ptk/UpdateEvent + (update [_ state] + (select-keys state [:route :router :session-id :history])) + + ptk/WatchEvent + (watch [_ state s] + (rx/of (rt/nav :auth-login))) + + ptk/EffectEvent + (effect [_ state s] + (reset! storage {}) + (i18n/reset-locale)))) + +(defn logout + [] + (ptk/reify ::logout + ptk/WatchEvent + (watch [_ state s] + (->> (rp/mutation :logout) + (rx/delay-at-least 300) + (rx/catch (constantly (rx/of 1))) + (rx/map logged-out))))) + +;; --- EVENT: register + +(s/def ::invitation-token ::us/not-empty-string) + +(s/def ::register + (s/keys :req-un [::fullname ::password ::email] + :opt-un [::invitation-token])) + +(defn register + "Create a register event instance." + [data] + (s/assert ::register data) + (ptk/reify ::register + ptk/WatchEvent + (watch [_ state stream] + (let [{:keys [on-error on-success] + :or {on-error identity + on-success identity}} (meta data)] + (->> (rp/mutation :register-profile data) + (rx/tap on-success) + (rx/catch on-error)))))) ;; --- Update Profile @@ -231,3 +360,70 @@ (watch [_ state stream] (->> (rp/query :team-users {:team-id team-id}) (rx/map #(partial fetched %))))))) + +;; --- EVENT: request-account-deletion + +(defn request-account-deletion + [params] + (ptk/reify ::request-account-deletion + ptk/WatchEvent + (watch [_ state stream] + (let [{:keys [on-error on-success] + :or {on-error rx/throw + on-success identity}} (meta params)] + (->> (rp/mutation :delete-profile {}) + (rx/tap on-success) + (rx/catch on-error)))))) + + +;; --- EVENT: request-profile-recovery + +(s/def ::request-profile-recovery + (s/keys :req-un [::email])) + +(defn request-profile-recovery + [data] + (us/verify ::request-profile-recovery data) + (ptk/reify ::request-profile-recovery + ptk/WatchEvent + (watch [_ state stream] + (let [{:keys [on-error on-success] + :or {on-error rx/throw + on-success identity}} (meta data)] + + (->> (rp/mutation :request-profile-recovery data) + (rx/tap on-success) + (rx/catch on-error)))))) + +;; --- EVENT: recover-profile (Password) + +(s/def ::token string?) +(s/def ::recover-profile + (s/keys :req-un [::password ::token])) + +(defn recover-profile + [{:keys [token password] :as data}] + (us/verify ::recover-profile data) + (ptk/reify ::recover-profile + ptk/WatchEvent + (watch [_ state stream] + (let [{:keys [on-error on-success] + :or {on-error rx/throw + on-success identity}} (meta data)] + (->> (rp/mutation :recover-profile data) + (rx/tap on-success) + (rx/catch (fn [err] + (on-error) + (rx/empty)))))))) + +;; --- EVENT: crete-demo-profile + +(defn create-demo-profile + [] + (ptk/reify ::create-demo-profile + ptk/WatchEvent + (watch [_ state stream] + (->> (rp/mutation :create-demo-profile {}) + (rx/map login))))) + + diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index d87f453d6..ff774f748 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -249,21 +249,26 @@ ;; Workspace Page CRUD ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(def create-empty-page - (ptk/reify ::create-empty-page - ptk/WatchEvent - (watch [this state stream] - (let [id (uuid/next) - pages (get-in state [:workspace-data :pages-index]) - unames (dwc/retrieve-used-names pages) - name (dwc/generate-unique-name unames "Page") +(defn create-page + [{:keys [file-id]}] + (let [id (uuid/next)] + (ptk/reify ::create-page + IDeref + (-deref [_] + {:id id :file-id file-id}) - rchange {:type :add-page - :id id - :name name} - uchange {:type :del-page - :id id}] - (rx/of (dch/commit-changes [rchange] [uchange] {:commit-local? true})))))) + ptk/WatchEvent + (watch [this state stream] + (let [pages (get-in state [:workspace-data :pages-index]) + unames (dwc/retrieve-used-names pages) + name (dwc/generate-unique-name unames "Page") + + rchange {:type :add-page + :id id + :name name} + uchange {:type :del-page + :id id}] + (rx/of (dch/commit-changes [rchange] [uchange] {:commit-local? true}))))))) (defn duplicate-page [page-id] (ptk/reify ::duplicate-page diff --git a/frontend/src/app/main/repo.cljs b/frontend/src/app/main/repo.cljs index 2a35a53f1..8b5980ed5 100644 --- a/frontend/src/app/main/repo.cljs +++ b/frontend/src/app/main/repo.cljs @@ -15,7 +15,7 @@ [beicon.core :as rx] [cuerdas.core :as str])) -(defn- handle-response +(defn handle-response [{:keys [status body] :as response}] (cond (= 204 status) diff --git a/frontend/src/app/main/store.cljs b/frontend/src/app/main/store.cljs index db162221f..6a4ea6534 100644 --- a/frontend/src/app/main/store.cljs +++ b/frontend/src/app/main/store.cljs @@ -7,16 +7,13 @@ (ns app.main.store (:require-macros [app.main.store]) (:require - [beicon.core :as rx] - [okulary.core :as l] - [potok.core :as ptk] - [cuerdas.core :as str] [app.common.data :as d] [app.common.pages :as cp] - [app.common.pages.helpers :as helpers] - [app.common.uuid :as uuid] - [app.util.storage :refer [storage]] - [app.util.debug :refer [debug? debug-exclude-events logjs]])) + [app.util.debug :refer [debug? debug-exclude-events logjs]] + [beicon.core :as rx] + [cuerdas.core :as str] + [okulary.core :as l] + [potok.core :as ptk])) (enable-console-print!) @@ -26,12 +23,6 @@ (defonce state (ptk/store {:resolve ptk/resolve})) (defonce stream (ptk/input-stream state)) -(defn ^boolean is-logged? - [pdata] - (and (some? pdata) - (uuid? (:id pdata)) - (not= uuid/zero (:id pdata)))) - (when *assert* (defonce debug-subscription (->> stream @@ -53,16 +44,6 @@ [& events] #(apply ptk/emit! state events)) -(def initial-state - {:session-id (uuid/next) - :profile (:profile storage)}) - -(defn init - "Initialize the state materialization." - ([] (init {})) - ([props] - (emit! #(merge % initial-state props)))) - (defn ^:export dump-state [] (logjs "state" @state)) diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index 9c7d35f7e..9b2c772a5 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -12,8 +12,9 @@ [app.common.spec :as us] [app.common.uuid :as uuid] [app.config :as cfg] - [app.main.data.auth :refer [logout]] + [app.main.data.users :as du] [app.main.data.messages :as dm] + [app.main.data.events :as ev] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.auth :refer [auth]] @@ -106,6 +107,7 @@ (mf/defc main-page {::mf/wrap [#(mf/catch % {:fallback on-main-error})]} [{:keys [route] :as props}] + [:& (mf/provider ctx/current-route) {:value route} (case (get-in route [:data :name]) (:auth-login @@ -214,7 +216,7 @@ ;; all profile data and redirect the user to the login page. (defmethod ptk/handle-error :authentication [error] - (ts/schedule (st/emitf (logout)))) + (ts/schedule (st/emitf (du/logout)))) ;; Error that happens on an active bussines model validation does not ;; passes an validation (example: profile can't leave a team). From diff --git a/frontend/src/app/main/ui/auth.cljs b/frontend/src/app/main/ui/auth.cljs index f5c01f034..c5f9cf846 100644 --- a/frontend/src/app/main/ui/auth.cljs +++ b/frontend/src/app/main/ui/auth.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.auth (:require [app.common.uuid :as uuid] - [app.main.data.auth :as da] [app.main.data.messages :as dm] [app.main.data.users :as du] [app.main.repo :as rp] @@ -19,7 +18,6 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.forms :as fm] - [app.util.storage :refer [cache]] [app.util.i18n :as i18n :refer [t]] [app.util.router :as rt] [app.util.timers :as ts] diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index 5dd40cecc..3b809e986 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -6,22 +6,22 @@ (ns app.main.ui.auth.login (:require - [cljs.spec.alpha :as s] - [beicon.core :as rx] - [rumext.alpha :as mf] - [app.config :as cfg] [app.common.spec :as us] - [app.main.ui.icons :as i] - [app.main.data.auth :as da] + [app.config :as cfg] + [app.main.data.messages :as dm] + [app.main.data.users :as du] [app.main.repo :as rp] [app.main.store :as st] - [app.main.ui.messages :as msgs] - [app.main.data.messages :as dm] [app.main.ui.components.forms :as fm] - [app.util.object :as obj] + [app.main.ui.icons :as i] + [app.main.ui.messages :as msgs] [app.util.dom :as dom] [app.util.i18n :refer [tr t]] - [app.util.router :as rt])) + [app.util.object :as obj] + [app.util.router :as rt] + [beicon.core :as rx] + [cljs.spec.alpha :as s] + [rumext.alpha :as mf])) (s/def ::email ::us/email) (s/def ::password ::us/not-empty-string) @@ -45,7 +45,7 @@ (rx/subs (fn [profile] (if-let [token (:invitation-token profile)] (st/emit! (rt/nav :auth-verify-token {} {:token token})) - (st/emit! (da/logged-in profile)))) + (st/emit! (du/login-from-token {:profile profile})))) (fn [{:keys [type code] :as error}] (cond (and (= type :restriction) @@ -72,7 +72,7 @@ (reset! error nil) (let [params (with-meta (:clean-data @form) {:on-error on-error})] - (st/emit! (da/login params))))) + (st/emit! (du/login params))))) on-submit-ldap (mf/use-callback @@ -149,15 +149,13 @@ [:div.links [:div.link-entry - [:a {:on-click #(st/emit! (rt/nav :auth-recovery-request)) - :tab-index "5"} + [:a {:on-click #(st/emit! (rt/nav :auth-recovery-request))} (tr "auth.forgot-password")]] (when cfg/registration-enabled [:div.link-entry [:span (tr "auth.register") " "] - [:a {:on-click #(st/emit! (rt/nav :auth-register {} params)) - :tab-index "6"} + [:a {:on-click #(st/emit! (rt/nav :auth-register {} params))} (tr "auth.register-submit")]])] [:& login-buttons {:params params}] @@ -166,6 +164,5 @@ [:div.links.demo [:div.link-entry [:span (tr "auth.create-demo-profile") " "] - [:a {:on-click (st/emitf da/create-demo-profile) - :tab-index "6"} + [:a {:on-click (st/emitf (du/create-demo-profile))} (tr "auth.create-demo-account")]]])]]) diff --git a/frontend/src/app/main/ui/auth/recovery.cljs b/frontend/src/app/main/ui/auth/recovery.cljs index f437b7fe5..704005986 100644 --- a/frontend/src/app/main/ui/auth/recovery.cljs +++ b/frontend/src/app/main/ui/auth/recovery.cljs @@ -6,18 +6,18 @@ (ns app.main.ui.auth.recovery (:require - [cljs.spec.alpha :as s] - [cuerdas.core :as str] - [rumext.alpha :as mf] - [app.main.ui.icons :as i] [app.common.spec :as us] - [app.main.data.auth :as uda] [app.main.data.messages :as dm] + [app.main.data.users :as du] [app.main.store :as st] [app.main.ui.components.forms :as fm] + [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [t tr]] - [app.util.router :as rt])) + [app.util.router :as rt] + [cljs.spec.alpha :as s] + [cuerdas.core :as str] + [rumext.alpha :as mf])) (s/def ::password-1 ::us/not-empty-string) (s/def ::password-2 ::us/not-empty-string) @@ -54,7 +54,7 @@ :on-success on-success} params {:token (get-in @form [:clean-data :token]) :password (get-in @form [:clean-data :password-2])}] - (st/emit! (uda/recover-profile (with-meta params mdata))))) + (st/emit! (du/recover-profile (with-meta params mdata))))) (mf/defc recovery-form [{:keys [locale params] :as props}] diff --git a/frontend/src/app/main/ui/auth/recovery_request.cljs b/frontend/src/app/main/ui/auth/recovery_request.cljs index 2d8ae58d1..637bbc852 100644 --- a/frontend/src/app/main/ui/auth/recovery_request.cljs +++ b/frontend/src/app/main/ui/auth/recovery_request.cljs @@ -7,8 +7,8 @@ (ns app.main.ui.auth.recovery-request (:require [app.common.spec :as us] - [app.main.data.auth :as uda] [app.main.data.messages :as dm] + [app.main.data.users :as du] [app.main.store :as st] [app.main.ui.components.forms :as fm] [app.main.ui.icons :as i] @@ -59,7 +59,7 @@ params (with-meta cdata {:on-success #(on-success cdata %) :on-error #(on-error cdata %)})] - (st/emit! (uda/request-profile-recovery params)))))] + (st/emit! (du/request-profile-recovery params)))))] [:& fm/form {:on-submit on-submit :form form} diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index a8321a6a0..97c1aec2e 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -8,7 +8,6 @@ (:require [app.common.spec :as us] [app.config :as cfg] - [app.main.data.auth :as da] [app.main.data.users :as du] [app.main.data.messages :as dm] [app.main.store :as st] @@ -93,7 +92,7 @@ (let [data (with-meta (:clean-data @form) {:on-error (partial on-error form) :on-success (partial on-success form)})] - (st/emit! (da/register data)))))] + (st/emit! (du/register data)))))] [:& fm/form {:on-submit on-submit @@ -158,7 +157,7 @@ (when cfg/allow-demo-users [:div.link-entry [:span (tr "auth.create-demo-profile") " "] - [:a {:on-click #(st/emit! da/create-demo-profile) + [:a {:on-click #(st/emit! (du/create-demo-profile)) :tab-index "5"} (tr "auth.create-demo-account")]]) diff --git a/frontend/src/app/main/ui/auth/verify_token.cljs b/frontend/src/app/main/ui/auth/verify_token.cljs index a926cf85b..bba45581a 100644 --- a/frontend/src/app/main/ui/auth/verify_token.cljs +++ b/frontend/src/app/main/ui/auth/verify_token.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.auth.verify-token (:require [app.common.uuid :as uuid] - [app.main.data.auth :as da] [app.main.data.messages :as dm] [app.main.data.users :as du] [app.main.repo :as rp] @@ -21,7 +20,6 @@ [app.util.forms :as fm] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] - [app.util.storage :refer [cache]] [app.util.timers :as ts] [beicon.core :as rx] [cljs.spec.alpha :as s] @@ -33,7 +31,7 @@ [data] (let [msg (tr "dashboard.notifications.email-verified-successfully")] (ts/schedule 100 #(st/emit! (dm/success msg))) - (st/emit! (da/login-from-token data)))) + (st/emit! (du/login-from-token data)))) (defmethod handle-token :change-email [data] @@ -44,7 +42,7 @@ (defmethod handle-token :auth [tdata] - (st/emit! (da/login-from-token tdata))) + (st/emit! (du/login-from-token tdata))) (defmethod handle-token :team-invitation [tdata] diff --git a/frontend/src/app/main/ui/dashboard/comments.cljs b/frontend/src/app/main/ui/dashboard/comments.cljs index 6eec7fc75..48703fdf2 100644 --- a/frontend/src/app/main/ui/dashboard/comments.cljs +++ b/frontend/src/app/main/ui/dashboard/comments.cljs @@ -10,7 +10,6 @@ [app.common.data :as d] [app.common.spec :as us] [app.config :as cfg] - [app.main.data.auth :as da] [app.main.data.dashboard :as dd] [app.main.data.workspace :as dw] [app.main.data.workspace.comments :as dwcm] diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index 459b7949d..b9dc8446e 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -9,7 +9,6 @@ [app.common.data :as d] [app.common.spec :as us] [app.config :as cfg] - [app.main.data.auth :as da] [app.main.data.comments :as dcm] [app.main.data.dashboard :as dd] [app.main.data.messages :as dm] @@ -215,7 +214,7 @@ team-selected (mf/use-callback (fn [team-id] - (da/set-current-team! team-id) + (du/set-current-team! team-id) (st/emit! (rt/nav :dashboard-projects {:team-id team-id}))))] [:ul.dropdown.teams-dropdown @@ -322,7 +321,7 @@ (mf/deps team profile) (fn [] (let [team-id (:default-team-id profile)] - (da/set-current-team! team-id) + (du/set-current-team! team-id) (st/emit! (modal/hide) (du/fetch-teams) (rt/nav :dashboard-projects {:team-id team-id}))))) @@ -548,7 +547,7 @@ [:li {:on-click (partial on-click :settings-password)} [:span.icon i/lock] [:span.text (tr "labels.password")]] - [:li {:on-click (partial on-click (da/logout))} + [:li {:on-click (partial on-click (du/logout))} [:span.icon i/exit] [:span.text (tr "labels.logout")]] diff --git a/frontend/src/app/main/ui/settings/change_email.cljs b/frontend/src/app/main/ui/settings/change_email.cljs index 36402814e..46726c87f 100644 --- a/frontend/src/app/main/ui/settings/change_email.cljs +++ b/frontend/src/app/main/ui/settings/change_email.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.settings.change-email (:require [app.common.spec :as us] - [app.main.data.auth :as da] [app.main.data.messages :as dm] [app.main.data.modal :as modal] [app.main.data.users :as du] diff --git a/frontend/src/app/main/ui/settings/delete_account.cljs b/frontend/src/app/main/ui/settings/delete_account.cljs index abf29ccc5..fe3ef3c59 100644 --- a/frontend/src/app/main/ui/settings/delete_account.cljs +++ b/frontend/src/app/main/ui/settings/delete_account.cljs @@ -6,7 +6,6 @@ (ns app.main.ui.settings.delete-account (:require - [app.main.data.auth :as da] [app.main.data.messages :as dm] [app.main.data.modal :as modal] [app.main.data.users :as du] @@ -41,7 +40,7 @@ on-accept (mf/use-callback (st/emitf (modal/hide) - (da/request-account-deletion + (du/request-account-deletion (with-meta {} {:on-error on-error :on-success on-success}))))] diff --git a/frontend/src/app/main/ui/settings/sidebar.cljs b/frontend/src/app/main/ui/settings/sidebar.cljs index 83d4993d5..ed5347091 100644 --- a/frontend/src/app/main/ui/settings/sidebar.cljs +++ b/frontend/src/app/main/ui/settings/sidebar.cljs @@ -7,8 +7,8 @@ (ns app.main.ui.settings.sidebar (:require [app.config :as cf] - [app.main.data.auth :as da] [app.main.data.modal :as modal] + [app.main.data.users :as du] [app.main.store :as st] [app.main.ui.dashboard.sidebar :refer [profile-section]] [app.main.ui.icons :as i] @@ -26,7 +26,7 @@ go-dashboard (mf/use-callback (mf/deps profile) - (st/emitf (rt/nav :dashboard-projects {:team-id (da/current-team-id profile)}))) + (st/emitf (rt/nav :dashboard-projects {:team-id (du/get-current-team-id profile)}))) go-settings-profile (mf/use-callback diff --git a/frontend/src/app/main/ui/static.cljs b/frontend/src/app/main/ui/static.cljs index 86f002d21..0cd9c0b5a 100644 --- a/frontend/src/app/main/ui/static.cljs +++ b/frontend/src/app/main/ui/static.cljs @@ -6,21 +6,21 @@ (ns app.main.ui.static (:require - [cljs.spec.alpha :as s] - [rumext.alpha :as mf] - [app.main.ui.context :as ctx] - [app.main.data.auth :as da] [app.main.data.messages :as dm] - [app.main.store :as st] + [app.main.data.users :as du] [app.main.refs :as refs] - [cuerdas.core :as str] + [app.main.store :as st] + [app.main.ui.context :as ctx] + [app.main.ui.icons :as i] [app.util.i18n :refer [tr]] [app.util.router :as rt] - [app.main.ui.icons :as i])) + [cljs.spec.alpha :as s] + [cuerdas.core :as str] + [rumext.alpha :as mf])) (defn- go-to-dashboard [profile] - (let [team-id (da/current-team-id profile)] + (let [team-id (du/get-current-team-id profile)] (st/emit! (rt/nav :dashboard-projects {:team-id team-id})))) (mf/defc not-found @@ -38,7 +38,7 @@ [:div.sign-info [:span (tr "labels.not-found.auth-info") " " [:b (:email profile)]] [:a.btn-primary.btn-small - {:on-click (st/emitf (da/logout))} + {:on-click (st/emitf (du/logout))} (tr "labels.sign-out")]]]]])) (mf/defc bad-gateway diff --git a/frontend/src/app/main/ui/viewer/header.cljs b/frontend/src/app/main/ui/viewer/header.cljs index 2644e620c..46a29b984 100644 --- a/frontend/src/app/main/ui/viewer/header.cljs +++ b/frontend/src/app/main/ui/viewer/header.cljs @@ -10,6 +10,7 @@ [app.common.uuid :as uuid] [app.config :as cfg] [app.main.data.comments :as dcm] + [app.main.data.events :as ev] [app.main.data.messages :as dm] [app.main.data.viewer :as dv] [app.main.data.viewer.shortcuts :as sc] @@ -23,6 +24,7 @@ [app.util.router :as rt] [app.util.webapi :as wapi] [cuerdas.core :as str] + [potok.core :as ptk] [rumext.alpha :as mf])) (mf/defc zoom-widget diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs index eb430cbf2..2cf441813 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs @@ -198,11 +198,13 @@ (mf/defc sitemap [{:keys [layout] :as props}] - (let [create (mf/use-callback #(st/emit! dw/create-empty-page)) + (let [file (mf/deref refs/workspace-file) + create (mf/use-callback + (mf/deps file) + (st/emitf (dw/create-page {:file-id (:id file) + :project-id (:project-id file)}))) show-pages? (mf/use-state true) - file (mf/deref refs/workspace-file) - toggle-pages (mf/use-callback #(reset! show-pages? not))] diff --git a/frontend/src/app/util/i18n.cljs b/frontend/src/app/util/i18n.cljs index 88b7cc807..ebaf43b25 100644 --- a/frontend/src/app/util/i18n.cljs +++ b/frontend/src/app/util/i18n.cljs @@ -52,7 +52,7 @@ cfg/default-language)))) (defonce translations #js {}) -(defonce locale (l/atom (or (get storage ::locale) +(defonce locale (l/atom (or (get @storage ::locale) (autodetect)))) ;; The traslations `data` is a javascript object and should be treated diff --git a/frontend/src/app/util/router.cljs b/frontend/src/app/util/router.cljs index ab20b3d67..0fc55dc8f 100644 --- a/frontend/src/app/util/router.cljs +++ b/frontend/src/app/util/router.cljs @@ -58,29 +58,48 @@ ;; --- Navigate (Event) -(deftype Navigate [id params qparams replace] - ptk/UpdateEvent - (update [_ state] - (dissoc state :exception)) +(defn navigated + [match] + (ptk/reify ::navigated + IDeref + (-deref [_] match) - ptk/EffectEvent - (effect [_ state stream] - (let [router (:router state) - history (:history state) - path (resolve router id params qparams)] - (if ^boolean replace - (bhistory/replace-token! history path) - (bhistory/set-token! history path))))) + ptk/UpdateEvent + (update [_ state] + (assoc state :route match)))) + +(defn navigate* + [id params qparams replace] + (ptk/reify ::navigate + IDeref + (-deref [_] + {:id id + :path-params params + :query-params qparams + :replace replace}) + + ptk/UpdateEvent + (update [_ state] + (dissoc state :exception)) + + ptk/EffectEvent + (effect [_ state stream] + (let [router (:router state) + history (:history state) + path (resolve router id params qparams)] + (if ^boolean replace + (bhistory/replace-token! history path) + (bhistory/set-token! history path)))))) (defn nav ([id] (nav id nil nil)) ([id params] (nav id params nil)) - ([id params qparams] (Navigate. id params qparams false))) + ([id params qparams] (navigate* id params qparams false))) (defn nav' ([id] (nav id nil nil)) ([id params] (nav id params nil)) - ([id params qparams] (Navigate. id params qparams true))) + ([id params qparams] (navigate* id params qparams true))) (def navigate nav) diff --git a/frontend/src/app/util/theme.cljs b/frontend/src/app/util/theme.cljs index 93e76f8d5..deed7644a 100644 --- a/frontend/src/app/util/theme.cljs +++ b/frontend/src/app/util/theme.cljs @@ -17,7 +17,7 @@ [app.util.transit :as t] [app.util.storage :refer [storage]])) -(defonce theme (get storage ::theme cfg/default-theme)) +(defonce theme (get @storage ::theme cfg/default-theme)) (defonce theme-sub (rx/subject)) (defonce themes #js {})