mirror of
https://github.com/penpot/penpot.git
synced 2026-08-06 12:58:55 +00:00
Refactor messages (split ui and business logic).
This commit is contained in:
parent
6571c29c1d
commit
95c4f2fbc1
@ -15,9 +15,9 @@
|
|||||||
[uxbox.state :as st]
|
[uxbox.state :as st]
|
||||||
[uxbox.schema :as sc]
|
[uxbox.schema :as sc]
|
||||||
[uxbox.locales :refer (tr)]
|
[uxbox.locales :refer (tr)]
|
||||||
[uxbox.data.projects :as dp]
|
[uxbox.data.projects :as udp]
|
||||||
[uxbox.data.users :as udu]
|
[uxbox.data.users :as udu]
|
||||||
[uxbox.ui.messages :as uum]))
|
[uxbox.data.messages :as udm]))
|
||||||
|
|
||||||
;; --- Logged In
|
;; --- Logged In
|
||||||
|
|
||||||
|
|||||||
@ -12,8 +12,7 @@
|
|||||||
[uxbox.rstore :as rs]
|
[uxbox.rstore :as rs]
|
||||||
[uxbox.state :as st]
|
[uxbox.state :as st]
|
||||||
[uxbox.schema :as sc]
|
[uxbox.schema :as sc]
|
||||||
[uxbox.locales :refer (tr)]
|
[uxbox.locales :refer (tr)]))
|
||||||
[uxbox.ui.messages :as uum]))
|
|
||||||
|
|
||||||
;; --- Assign Errors
|
;; --- Assign Errors
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,6 @@
|
|||||||
[uxbox.data.pages :as udp]
|
[uxbox.data.pages :as udp]
|
||||||
[uxbox.state :as st]
|
[uxbox.state :as st]
|
||||||
[uxbox.state.project :as stpr]
|
[uxbox.state.project :as stpr]
|
||||||
[uxbox.ui.messages :as uum]
|
|
||||||
[uxbox.util.datetime :as dt]
|
[uxbox.util.datetime :as dt]
|
||||||
[uxbox.util.data :refer (without-keys
|
[uxbox.util.data :refer (without-keys
|
||||||
replace-by-id
|
replace-by-id
|
||||||
|
|||||||
112
src/uxbox/data/messages.cljs
Normal file
112
src/uxbox/data/messages.cljs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.data.messages
|
||||||
|
(:require [cuerdas.core :as str]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[beicon.core :as rx]
|
||||||
|
[lentes.core :as l]
|
||||||
|
[uxbox.rstore :as rs]))
|
||||||
|
|
||||||
|
;; --- Constants
|
||||||
|
|
||||||
|
(def ^:const +animation-timeout+ 600)
|
||||||
|
|
||||||
|
;; --- Message Event
|
||||||
|
|
||||||
|
(declare hide-message)
|
||||||
|
(declare show-message?)
|
||||||
|
|
||||||
|
(defrecord ShowMessage [data]
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(let [message (assoc data :state :visible)]
|
||||||
|
(assoc state :message message)))
|
||||||
|
|
||||||
|
rs/WatchEvent
|
||||||
|
(-apply-watch [_ state s]
|
||||||
|
(let [stoper (->> (rx/filter show-message? s)
|
||||||
|
(rx/take 1))]
|
||||||
|
(->> (rx/of (hide-message))
|
||||||
|
(rx/delay (:timeout data))
|
||||||
|
(rx/take-until stoper)))))
|
||||||
|
|
||||||
|
(defn show-message
|
||||||
|
[message]
|
||||||
|
(ShowMessage. message))
|
||||||
|
|
||||||
|
(defn show-message?
|
||||||
|
[v]
|
||||||
|
(instance? ShowMessage v))
|
||||||
|
|
||||||
|
(defn show-error
|
||||||
|
[message & {:keys [timeout] :or {timeout 3000}}]
|
||||||
|
(show-message {:content message
|
||||||
|
:type :error
|
||||||
|
:timeout timeout}))
|
||||||
|
|
||||||
|
(defn show-info
|
||||||
|
[message & {:keys [timeout] :or {timeout 3000}}]
|
||||||
|
(show-message {:content message
|
||||||
|
:type :info
|
||||||
|
:timeout timeout}))
|
||||||
|
|
||||||
|
(defn show-dialog
|
||||||
|
[message & {:keys [on-accept on-cancel]}]
|
||||||
|
(show-message {:content message
|
||||||
|
:on-accept on-accept
|
||||||
|
:on-cancel on-cancel
|
||||||
|
:timeout js/Number.MAX_SAFE_INTEGER
|
||||||
|
:type :dialog}))
|
||||||
|
|
||||||
|
;; --- Hide Message
|
||||||
|
|
||||||
|
(defrecord HideMessage [^:mutable canceled?]
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(update state :message
|
||||||
|
(fn [v]
|
||||||
|
(if (nil? v)
|
||||||
|
(do (set! canceled? true) nil)
|
||||||
|
(assoc v :state :hide)))))
|
||||||
|
|
||||||
|
rs/WatchEvent
|
||||||
|
(-apply-watch [_ state s]
|
||||||
|
(println "HideMessage.-apply-watch" canceled?)
|
||||||
|
(if canceled?
|
||||||
|
(rx/empty)
|
||||||
|
(->> (rx/of #(dissoc state :message))
|
||||||
|
(rx/delay +animation-timeout+)))))
|
||||||
|
|
||||||
|
(defn hide-message
|
||||||
|
[]
|
||||||
|
(HideMessage. false))
|
||||||
|
|
||||||
|
;; --- Direct Call Api
|
||||||
|
|
||||||
|
(defn error!
|
||||||
|
[& args]
|
||||||
|
(rs/emit! (apply show-error args)))
|
||||||
|
|
||||||
|
(defn info!
|
||||||
|
[& args]
|
||||||
|
(rs/emit! (apply show-info args)))
|
||||||
|
|
||||||
|
(defn dialog!
|
||||||
|
[& args]
|
||||||
|
(rs/emit! (apply show-dialog args)))
|
||||||
|
|
||||||
|
(defn close!
|
||||||
|
[]
|
||||||
|
(rs/emit! (hide-message)))
|
||||||
|
|
||||||
|
(defn error
|
||||||
|
[& args]
|
||||||
|
(rx/of (apply show-error args)))
|
||||||
|
|
||||||
|
(defn info
|
||||||
|
[& args]
|
||||||
|
(rx/of (apply show-info args)))
|
||||||
@ -17,7 +17,6 @@
|
|||||||
[uxbox.schema :as sc]
|
[uxbox.schema :as sc]
|
||||||
[uxbox.state :as st]
|
[uxbox.state :as st]
|
||||||
[uxbox.state.project :as stpr]
|
[uxbox.state.project :as stpr]
|
||||||
[uxbox.ui.messages :as uum]
|
|
||||||
[uxbox.util.datetime :as dt]
|
[uxbox.util.datetime :as dt]
|
||||||
[uxbox.util.data :refer (without-keys replace-by-id)]))
|
[uxbox.util.data :refer (without-keys replace-by-id)]))
|
||||||
|
|
||||||
@ -76,7 +75,7 @@
|
|||||||
(-> (sc/validate! data create-page-schema)
|
(-> (sc/validate! data create-page-schema)
|
||||||
(map->CreatePage)))
|
(map->CreatePage)))
|
||||||
|
|
||||||
;; --- Sync Page
|
;; --- Page Synced
|
||||||
|
|
||||||
(defrecord PageSynced [page]
|
(defrecord PageSynced [page]
|
||||||
rs/UpdateEvent
|
rs/UpdateEvent
|
||||||
@ -89,6 +88,8 @@
|
|||||||
[event]
|
[event]
|
||||||
(instance? PageSynced event))
|
(instance? PageSynced event))
|
||||||
|
|
||||||
|
;; --- Sync Page
|
||||||
|
|
||||||
(defrecord SyncPage [id]
|
(defrecord SyncPage [id]
|
||||||
rs/WatchEvent
|
rs/WatchEvent
|
||||||
(-apply-watch [this state s]
|
(-apply-watch [this state s]
|
||||||
|
|||||||
@ -14,8 +14,7 @@
|
|||||||
[uxbox.locales :refer (tr)]
|
[uxbox.locales :refer (tr)]
|
||||||
[uxbox.schema :as sc]
|
[uxbox.schema :as sc]
|
||||||
[uxbox.state.project :as stpr]
|
[uxbox.state.project :as stpr]
|
||||||
[uxbox.data.pages :as udp]
|
[uxbox.data.pages :as udp]))
|
||||||
[uxbox.ui.messages :as uum]))
|
|
||||||
|
|
||||||
;; --- Projects Fetched
|
;; --- Projects Fetched
|
||||||
|
|
||||||
|
|||||||
@ -12,8 +12,8 @@
|
|||||||
[uxbox.state :as st]
|
[uxbox.state :as st]
|
||||||
[uxbox.schema :as sc]
|
[uxbox.schema :as sc]
|
||||||
[uxbox.locales :refer (tr)]
|
[uxbox.locales :refer (tr)]
|
||||||
[uxbox.data.forms :as forms]
|
[uxbox.data.forms :as udf]
|
||||||
[uxbox.ui.messages :as uum]))
|
[uxbox.data.messages :as udm]))
|
||||||
|
|
||||||
;; --- Profile Fetched
|
;; --- Profile Fetched
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,7 @@
|
|||||||
(ns uxbox.rstore
|
(ns uxbox.rstore
|
||||||
"Reactive storage management architecture helpers."
|
"Reactive storage management architecture helpers."
|
||||||
(:require [beicon.core :as rx]
|
(:require [beicon.core :as rx]
|
||||||
[uxbox.locales :refer (tr)]
|
[uxbox.locales :refer (tr)]))
|
||||||
[uxbox.ui.messages :as uum]))
|
|
||||||
|
|
||||||
;; An abstraction for implement a simple state
|
;; An abstraction for implement a simple state
|
||||||
;; transition. The `-apply-update` function receives
|
;; transition. The `-apply-update` function receives
|
||||||
@ -99,7 +98,7 @@
|
|||||||
|
|
||||||
:else
|
:else
|
||||||
(do
|
(do
|
||||||
(uum/error (tr "errors.generic"))
|
(uxbox.data.messages/error! (tr "errors.generic"))
|
||||||
(println "Unexpected error: " error)
|
(println "Unexpected error: " error)
|
||||||
(js/console.log (.-stack error))
|
(js/console.log (.-stack error))
|
||||||
(rx/throw error))))
|
(rx/throw error))))
|
||||||
|
|||||||
@ -7,15 +7,14 @@
|
|||||||
[uxbox.state :as s]
|
[uxbox.state :as s]
|
||||||
[uxbox.rstore :as rs]
|
[uxbox.rstore :as rs]
|
||||||
[uxbox.data.auth :as da]
|
[uxbox.data.auth :as da]
|
||||||
|
[uxbox.data.messages :as udm]
|
||||||
[uxbox.util.dom :as dom]
|
[uxbox.util.dom :as dom]
|
||||||
[uxbox.ui.icons :as i]
|
[uxbox.ui.icons :as i]
|
||||||
[uxbox.ui.messages :as uum]
|
[uxbox.ui.messages :as uum]
|
||||||
[uxbox.ui.navigation :as nav]
|
[uxbox.ui.navigation :as nav]
|
||||||
[uxbox.ui.mixins :as mx]))
|
[uxbox.ui.mixins :as mx]))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; --- Login
|
||||||
;; Login
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(defn- login-submit
|
(defn- login-submit
|
||||||
[event local]
|
[event local]
|
||||||
|
|||||||
@ -1,106 +1,35 @@
|
|||||||
(ns uxbox.ui.messages
|
(ns uxbox.ui.messages
|
||||||
(:require [sablono.core :as html :refer-macros [html]]
|
(:require [sablono.core :as html :refer-macros [html]]
|
||||||
[rum.core :as rum]
|
[rum.core :as rum]
|
||||||
[cuerdas.core :as str]
|
[promesa.core :as p]
|
||||||
|
[lentes.core :as l]
|
||||||
|
[uxbox.state :as st]
|
||||||
|
[uxbox.data.messages :as udm]
|
||||||
[uxbox.ui.icons :as i]
|
[uxbox.ui.icons :as i]
|
||||||
[uxbox.ui.mixins :as mx]
|
[uxbox.ui.mixins :as mx]
|
||||||
[uxbox.util.data :refer (classnames)]
|
[uxbox.util.data :refer (classnames)]
|
||||||
[uxbox.util.dom :as dom]))
|
[uxbox.util.dom :as dom]))
|
||||||
|
|
||||||
;; --- Constants
|
;; --- Lenses
|
||||||
|
|
||||||
(defonce +message+ (atom nil))
|
(def ^:const ^:private message-l
|
||||||
|
(-> (l/key :message)
|
||||||
(def ^:const +animation-timeout+ 600)
|
(l/focus-atom st/state)))
|
||||||
|
|
||||||
;; --- Helpers
|
|
||||||
|
|
||||||
(defn set-timeout!
|
|
||||||
[ms callback]
|
|
||||||
(js/setTimeout callback ms))
|
|
||||||
|
|
||||||
(defn abort-timeout!
|
|
||||||
[v]
|
|
||||||
(when v
|
|
||||||
(js/clearTimeout v)))
|
|
||||||
|
|
||||||
;; --- Public Api
|
|
||||||
|
|
||||||
(defn- clean-prev-msgstate!
|
|
||||||
[message]
|
|
||||||
(let [type (namespace (:type message))]
|
|
||||||
(case type
|
|
||||||
"notification"
|
|
||||||
(do
|
|
||||||
(abort-timeout! (:tsem-main message))
|
|
||||||
(abort-timeout! (:tsem message)))
|
|
||||||
|
|
||||||
"dialog"
|
|
||||||
(abort-timeout! (:tsem message)))))
|
|
||||||
|
|
||||||
(defn error
|
|
||||||
([message] (error message nil))
|
|
||||||
([message {:keys [timeout] :or {timeout 6000}}]
|
|
||||||
(when-let [prev @+message+]
|
|
||||||
(clean-prev-msgstate! prev))
|
|
||||||
(let [timeout' (+ timeout +animation-timeout+)
|
|
||||||
tsem-main (set-timeout! timeout' #(reset! +message+ nil))
|
|
||||||
tsem (set-timeout! timeout #(swap! +message+ assoc :state :hide))]
|
|
||||||
(reset! +message+ {:type :notification/error
|
|
||||||
:state :normal
|
|
||||||
:tsem-main tsem-main
|
|
||||||
:tsem tsem
|
|
||||||
:content message}))))
|
|
||||||
|
|
||||||
(defn info
|
|
||||||
([message] (info message nil))
|
|
||||||
([message {:keys [timeout] :or {timeout 6000}}]
|
|
||||||
(when-let [prev @+message+]
|
|
||||||
(clean-prev-msgstate! prev))
|
|
||||||
(let [timeout' (+ timeout +animation-timeout+)
|
|
||||||
tsem-main (set-timeout! timeout' #(reset! +message+ nil))
|
|
||||||
tsem (set-timeout! timeout #(swap! +message+ assoc :state :hide))]
|
|
||||||
(reset! +message+ {:type :notification/info
|
|
||||||
:state :normal
|
|
||||||
:tsem-main tsem-main
|
|
||||||
:tsem tsem
|
|
||||||
:content message}))))
|
|
||||||
|
|
||||||
(defn dialog
|
|
||||||
[& {:keys [message on-accept on-cancel]
|
|
||||||
:or {on-cancel (constantly nil)}
|
|
||||||
:as opts}]
|
|
||||||
{:pre [(ifn? on-accept)
|
|
||||||
(string? message)]}
|
|
||||||
(when-let [prev @+message+]
|
|
||||||
(clean-prev-msgstate! prev))
|
|
||||||
(reset! +message+ {:type :dialog/simple
|
|
||||||
:state :normal
|
|
||||||
:content message
|
|
||||||
:on-accept on-accept
|
|
||||||
:on-cancel on-cancel}))
|
|
||||||
(defn close
|
|
||||||
[]
|
|
||||||
(when @+message+
|
|
||||||
(let [timeout +animation-timeout+
|
|
||||||
tsem (set-timeout! timeout #(reset! +message+ nil))]
|
|
||||||
(swap! +message+ assoc
|
|
||||||
:state :hide
|
|
||||||
:tsem tsem))))
|
|
||||||
|
|
||||||
;; --- Notification Component
|
;; --- Notification Component
|
||||||
|
|
||||||
(defn notification-render
|
(defn notification-render
|
||||||
[own message]
|
[own {:keys [type] :as message}]
|
||||||
(let [msgtype (name (:type message))
|
(let [classes (classnames :error (= type :error)
|
||||||
classes (classnames :error (= msgtype "error")
|
:info (= type :info)
|
||||||
:info (= msgtype "info")
|
|
||||||
:hide-message (= (:state message) :hide)
|
:hide-message (= (:state message) :hide)
|
||||||
:quick true)]
|
:quick true)
|
||||||
|
close #(udm/close!)]
|
||||||
(html
|
(html
|
||||||
[:div.message {:class classes}
|
[:div.message {:class classes}
|
||||||
[:div.message-body
|
[:div.message-body
|
||||||
[:span.close i/close]
|
[:span.close {:on-clock close}
|
||||||
|
i/close]
|
||||||
[:span (:content message)]]])))
|
[:span (:content message)]]])))
|
||||||
|
|
||||||
(def ^:private notification-box
|
(def ^:private notification-box
|
||||||
@ -114,21 +43,21 @@
|
|||||||
(defn dialog-render
|
(defn dialog-render
|
||||||
[own {:keys [on-accept on-cancel] :as message}]
|
[own {:keys [on-accept on-cancel] :as message}]
|
||||||
(let [classes (classnames :info true
|
(let [classes (classnames :info true
|
||||||
:hide-message (= (:state message) :hide))
|
:hide-message (= (:state message) :hide))]
|
||||||
local (:rum/local own)]
|
|
||||||
(letfn [(accept [event]
|
(letfn [(accept [event]
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(close)
|
(on-accept)
|
||||||
(on-accept))
|
(p/schedule 0 udm/close!))
|
||||||
|
|
||||||
(cancel [event]
|
(cancel [event]
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(close)
|
|
||||||
(when on-cancel
|
(when on-cancel
|
||||||
(on-cancel)))]
|
(on-cancel))
|
||||||
|
(p/schedule 0 udm/close!))]
|
||||||
(html
|
(html
|
||||||
[:div.message {:class classes}
|
[:div.message {:class classes}
|
||||||
[:div.message-body
|
[:div.message-body
|
||||||
[:span.close i/close]
|
[:span.close {:on-click cancel} i/close]
|
||||||
[:span (:content message)]
|
[:span (:content message)]
|
||||||
[:div.message-action
|
[:div.message-action
|
||||||
[:a.btn-transparent.btn-small
|
[:a.btn-transparent.btn-small
|
||||||
@ -148,11 +77,11 @@
|
|||||||
|
|
||||||
(defn messages-render
|
(defn messages-render
|
||||||
[own]
|
[own]
|
||||||
(when-let [message (rum/react +message+)]
|
(let [message (rum/react message-l)]
|
||||||
(case (namespace (:type message))
|
(case (:type message)
|
||||||
"notification" (notification-box message)
|
:error (notification-box message)
|
||||||
"dialog" (dialog-box message)
|
:dialog (dialog-box message)
|
||||||
(throw (ex-info "Invalid message type" message)))))
|
nil)))
|
||||||
|
|
||||||
(def ^:const messages
|
(def ^:const messages
|
||||||
(mx/component
|
(mx/component
|
||||||
|
|||||||
@ -18,8 +18,8 @@
|
|||||||
[uxbox.data.workspace :as dw]
|
[uxbox.data.workspace :as dw]
|
||||||
[uxbox.data.pages :as udp]
|
[uxbox.data.pages :as udp]
|
||||||
[uxbox.data.history :as udh]
|
[uxbox.data.history :as udh]
|
||||||
|
[uxbox.data.messages :as udm]
|
||||||
[uxbox.ui.workspace.base :as wb]
|
[uxbox.ui.workspace.base :as wb]
|
||||||
[uxbox.ui.messages :as msg]
|
|
||||||
[uxbox.ui.icons :as i]
|
[uxbox.ui.icons :as i]
|
||||||
[uxbox.ui.mixins :as mx]
|
[uxbox.ui.mixins :as mx]
|
||||||
[uxbox.util.datetime :as dt]
|
[uxbox.util.datetime :as dt]
|
||||||
@ -94,11 +94,11 @@
|
|||||||
(let [[page history] (:rum/props own)]
|
(let [[page history] (:rum/props own)]
|
||||||
(if-let [version (:selected history)]
|
(if-let [version (:selected history)]
|
||||||
(let [selected (get-in history [:by-version version])]
|
(let [selected (get-in history [:by-version version])]
|
||||||
(msg/dialog
|
(udm/dialog!
|
||||||
:message (tr "history.alert-message" version)
|
(tr "history.alert-message" version)
|
||||||
:on-accept #(rs/emit! (udh/apply-selected-history (:id page)))
|
:on-accept #(rs/emit! (udh/apply-selected-history (:id page)))
|
||||||
:on-cancel #(rs/emit! (udh/discard-selected-history (:id page)))))
|
:on-cancel #(rs/emit! (udh/discard-selected-history (:id page)))))
|
||||||
(msg/close))
|
(udm/close!))
|
||||||
own))
|
own))
|
||||||
|
|
||||||
(def history-list
|
(def history-list
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user