0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-25 14:11:33 -05:00

♻️ Refactor naming and location of flash notifications

This commit is contained in:
Andrey Antukh 2024-07-22 19:04:15 +02:00
parent 3917215952
commit f187012469
40 changed files with 258 additions and 275 deletions

View file

@ -9,8 +9,8 @@
(:require
[app.common.types.components-list :as ctkl]
[app.config :as cf]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.features :as features]
[app.main.repo :as rp]
[app.main.store :as st]
@ -61,7 +61,7 @@
(defn hide-notifications!
[]
(st/emit! msg/hide))
(st/emit! (ntf/hide)))
(defn handle-notification
[{:keys [message code level] :as params}]
@ -72,7 +72,7 @@
:upgrade-version
(when (or (not= (:version params) (:full cf/version))
(true? (:force params)))
(rx/of (msg/dialog
(rx/of (ntf/dialog
:content (tr "notifications.by-code.upgrade-version")
:controls :inline-actions
:notification-type :inline
@ -81,7 +81,7 @@
:tag :notification)))
:maintenance
(rx/of (msg/dialog
(rx/of (ntf/dialog
:content (tr "notifications.by-code.maintenance")
:controls :inline-actions
:type level
@ -89,7 +89,7 @@
:callback hide-notifications!}]
:tag :notification))
(rx/of (msg/dialog
(rx/of (ntf/dialog
:content message
:controls :close
:type level

View file

@ -13,7 +13,7 @@
[app.common.media :as cm]
[app.common.uuid :as uuid]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.fonts :as fonts]
[app.main.repo :as rp]
[app.main.store :as st]
@ -183,7 +183,7 @@
#(when
(not-empty %)
(st/emit!
(msg/error
(ntf/error
(if (> (count %) 1)
(tr "errors.bad-font-plural" (str/join ", " %))
(tr "errors.bad-font" (first %)))))))

View file

@ -8,7 +8,7 @@
(:require
[app.common.exceptions :as ex]
[app.common.media :as cm]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.store :as st]
[app.util.i18n :refer [tr]]
[beicon.v2.core :as rx]
@ -46,14 +46,14 @@
(defn notify-start-loading
[]
(st/emit! (msg/show {:content (tr "media.loading")
(st/emit! (ntf/show {:content (tr "media.loading")
:notification-type :toast
:type :info
:timeout nil})))
(defn notify-finished-loading
[]
(st/emit! msg/hide))
(st/emit! (ntf/hide)))
(defn process-error
[error]
@ -69,4 +69,4 @@
:else
(tr "errors.unexpected-error"))]
(rx/of (msg/error msg))))
(rx/of (ntf/error msg))))

View file

@ -4,7 +4,7 @@
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.data.messages
(ns app.main.data.notifications
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
@ -17,14 +17,14 @@
(def default-timeout 7000)
(def ^:private schema:message
[:map {:title "Message"}
[:type [::sm/one-of #{:success :error :info :warning}]]
(def ^:private schema:notification
[:map {:title "Notification"}
[:level [::sm/one-of #{:success :error :info :warning}]]
[:status {:optional true}
[::sm/one-of #{:visible :hide}]]
[:position {:optional true}
[::sm/one-of #{:fixed :floating :inline}]]
[:notification-type {:optional true}
[:type {:optional true}
[::sm/one-of #{:inline :context :toast}]]
[:controls {:optional true}
[::sm/one-of #{:none :close :inline-actions :bottom-actions}]]
@ -43,20 +43,21 @@
[:label :string]
[:callback ::sm/fn]]]]])
(def ^:private valid-message?
(sm/validator schema:message))
(def ^:private valid-notification?
(sm/validator schema:notification))
(defn show
[data]
(dm/assert!
"expected valid message map"
(valid-message? data))
"expected valid notification map"
(valid-notification? data))
(ptk/reify ::show
ptk/UpdateEvent
(update [_ state]
(let [message (assoc data :status :visible)]
(assoc state :message message)))
(let [notification (assoc data :status :visible)]
(assoc state :notification notification)))
ptk/WatchEvent
(watch [_ _ stream]
@ -64,42 +65,39 @@
(let [stopper (rx/filter (ptk/type? ::hide) stream)]
(->> stream
(rx/filter (ptk/type? :app.util.router/navigate))
(rx/map (constantly hide))
(rx/map (fn [_] (hide)))
(rx/take-until stopper)))
(when (:timeout data)
(let [stopper (rx/filter (ptk/type? ::show) stream)]
(->> (rx/of hide)
(->> (rx/of (hide))
(rx/delay (:timeout data))
(rx/take-until stopper))))))))
(def hide
(defn hide
[& {:keys [tag]}]
(ptk/reify ::hide
ptk/UpdateEvent
(update [_ state]
(dissoc state :message))))
(defn hide-tag
[tag]
(ptk/reify ::hide-tag
ptk/WatchEvent
(watch [_ state _]
(let [message (get state :message)]
(when (= (:tag message) tag)
(rx/of hide))))))
(if (some? tag)
(let [notification (get state :notification)]
(if (= tag (:tag notification))
(dissoc state :notification)
state))
(dissoc state :notification)))))
(defn error
([content]
(show {:content content
:type :error
:notification-type :toast
:level :error
:type :toast
:position :fixed})))
(defn info
([content] (info content {}))
([content {:keys [timeout] :or {timeout default-timeout}}]
(show {:content content
:type :info
:notification-type :toast
:level :info
:type :toast
:position :fixed
:timeout timeout})))
@ -107,8 +105,8 @@
([content] (success content {}))
([content {:keys [timeout] :or {timeout default-timeout}}]
(show {:content content
:type :success
:notification-type :toast
:level :success
:type :toast
:position :fixed
:timeout timeout})))
@ -116,31 +114,19 @@
([content] (warn content {}))
([content {:keys [timeout] :or {timeout default-timeout}}]
(show {:content content
:type :warning
:notification-type :toast
:level :warning
:type :toast
:position :fixed
:timeout timeout})))
(defn dialog
[& {:keys [content controls actions position tag type]
:or {controls :none position :floating type :info}}]
[& {:keys [content controls actions position tag level links]
:or {controls :none position :floating level :info}}]
(show (d/without-nils
{:content content
:type type
:level level
:links links
:position position
:controls controls
:actions actions
:tag tag})))
(defn info-dialog
[& {:keys [content controls links actions tag]
:or {controls :none links nil tag nil}}]
(show (d/without-nils
{:content content
:type :info
:position :floating
:notification-type :inline
:controls controls
:links links
:actions actions
:tag tag})))

View file

@ -15,7 +15,7 @@
[app.config :as cf]
[app.main.data.events :as ev]
[app.main.data.media :as di]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.websocket :as ws]
[app.main.features :as features]
[app.main.repo :as rp]
@ -711,4 +711,4 @@
(tr "errors.generic"))]
(rx/of (msg/warn hint))))))
(rx/of (ntf/warn hint))))))

View file

@ -39,8 +39,8 @@
[app.main.data.comments :as dcm]
[app.main.data.events :as ev]
[app.main.data.fonts :as df]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.persistence :as dps]
[app.main.data.users :as du]
[app.main.data.workspace.bool :as dwb]
@ -347,7 +347,7 @@
(log/debug :hint "initialize-file" :file-id file-id)
(let [stoper-s (rx/filter (ptk/type? ::finalize-file) stream)]
(rx/merge
(rx/of msg/hide
(rx/of (ntf/hide)
(features/initialize)
(dcm/retrieve-comment-threads file-id)
(fetch-bundle project-id file-id))
@ -1595,7 +1595,7 @@
(on-error [cause]
(let [data (ex-data cause)]
(if (:not-implemented data)
(rx/of (msg/warn (tr "errors.clipboard-not-implemented")))
(rx/of (ntf/warn (tr "errors.clipboard-not-implemented")))
(js/console.error "Clipboard error:" cause))
(rx/empty)))]

View file

@ -28,8 +28,8 @@
[app.main.data.changes :as dch]
[app.main.data.comments :as dc]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.workspace :as-alias dw]
[app.main.data.workspace.groups :as dwg]
[app.main.data.workspace.notifications :as-alias dwn]
@ -1016,7 +1016,7 @@
file))
(rx/concat
(rx/of (set-updating-library false)
(msg/hide-tag :sync-dialog))
(ntf/hide {:tag :sync-dialog}))
(when (seq (:redo-changes changes))
(rx/of (dch/commit-changes changes)))
(when-not (empty? updated-frames)
@ -1084,12 +1084,12 @@
(sync-file (:current-file-id state)
(:id library)))
libraries-need-sync))
(st/emit! msg/hide))
(st/emit! (ntf/hide)))
do-dismiss #(do (st/emit! ignore-sync)
(st/emit! msg/hide))]
(st/emit! (ntf/hide)))]
(when (seq libraries-need-sync)
(rx/of (msg/info-dialog
(rx/of (ntf/dialog
:content (tr "workspace.updates.there-are-updates")
:controls :inline-actions
:links [{:label (tr "workspace.updates.more-info")

View file

@ -22,7 +22,7 @@
[app.config :as cf]
[app.main.data.changes :as dch]
[app.main.data.media :as dmm]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
@ -169,25 +169,25 @@
(handle-media-error (ex-data error) on-error)
(cond
(= (:code error) :invalid-svg-file)
(rx/of (msg/error (tr "errors.media-type-not-allowed")))
(rx/of (ntf/error (tr "errors.media-type-not-allowed")))
(= (:code error) :media-type-not-allowed)
(rx/of (msg/error (tr "errors.media-type-not-allowed")))
(rx/of (ntf/error (tr "errors.media-type-not-allowed")))
(= (:code error) :unable-to-access-to-url)
(rx/of (msg/error (tr "errors.media-type-not-allowed")))
(rx/of (ntf/error (tr "errors.media-type-not-allowed")))
(= (:code error) :invalid-image)
(rx/of (msg/error (tr "errors.media-type-not-allowed")))
(rx/of (ntf/error (tr "errors.media-type-not-allowed")))
(= (:code error) :media-max-file-size-reached)
(rx/of (msg/error (tr "errors.media-too-large")))
(rx/of (ntf/error (tr "errors.media-too-large")))
(= (:code error) :media-type-mismatch)
(rx/of (msg/error (tr "errors.media-type-mismatch")))
(rx/of (ntf/error (tr "errors.media-type-mismatch")))
(= (:code error) :unable-to-optimize)
(rx/of (msg/error (:hint error)))
(rx/of (ntf/error (:hint error)))
(fn? on-error)
(on-error error)
@ -195,7 +195,7 @@
:else
(do
(.error js/console "ERROR" error)
(rx/of (msg/error (tr "errors.cannot-upload")))))))
(rx/of (ntf/error (tr "errors.cannot-upload")))))))
(def ^:private
@ -220,7 +220,7 @@
ptk/WatchEvent
(watch [_ _ _]
(rx/concat
(rx/of (msg/show {:content (tr "media.loading")
(rx/of (ntf/show {:content (tr "media.loading")
:notification-type :toast
:type :info
:timeout nil
@ -234,7 +234,7 @@
;; Every stream has its own sideeffect. We need to ignore the result
(rx/ignore)
(rx/catch #(handle-media-error % on-error))
(rx/finalize #(st/emit! (msg/hide-tag :media-loading))))))))
(rx/finalize #(st/emit! (ntf/hide :tag :media-loading))))))))
;; Deprecated in components-v2
(defn upload-media-asset
@ -254,8 +254,6 @@
:on-svg #(st/emit! (svg-uploaded % file-id position)))]
(process-media-objects params)))
(defn upload-fill-image
[file on-success]
(dm/assert!
@ -450,7 +448,7 @@
:id object-id}]
(rx/concat
(rx/of (msg/show {:content (tr "media.loading")
(rx/of (ntf/show {:content (tr "media.loading")
:notification-type :toast
:type :info
:timeout nil
@ -458,7 +456,7 @@
(->> (rp/cmd! :clone-file-media-object params)
(rx/tap on-success)
(rx/catch on-error)
(rx/finalize #(st/emit! (msg/hide-tag :media-loading)))))))))
(rx/finalize #(st/emit! (ntf/hide :tag :media-loading)))))))))
(defn create-svg-shape
[id name svg-string position]

View file

@ -24,6 +24,8 @@
[clojure.set :as set]
[potok.v2.core :as ptk]))
;; FIXME: this ns should be renamed to something different
(declare process-message)
(declare handle-presence)
(declare handle-pointer-update)

View file

@ -10,8 +10,8 @@
[app.common.exceptions :as ex]
[app.common.pprint :as pp]
[app.common.schema :as-alias sm]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.store :as st]
[app.util.globals :as glob]
@ -104,7 +104,7 @@
(let [msg (tr "errors.auth.unable-to-login")
uri (. (. js/document -location) -href)]
(st/emit! (du/logout {:capture-redirect true}))
(ts/schedule 500 #(st/emit! (msg/warn msg)))
(ts/schedule 500 #(st/emit! (ntf/warn msg)))
(ts/schedule 1000 #(swap! storage assoc :redirect-url uri))))
;; Error that happens on an active business model validation does not
@ -123,7 +123,7 @@
(= code :invalid-paste-data)
(let [message (tr "errors.paste-data-validation")]
(st/async-emit!
(msg/show {:content message
(ntf/show {:content message
:notification-type :toast
:type :error
:timeout 3000})))
@ -138,7 +138,7 @@
(defmethod ptk/handle-error :assertion
[error]
(ts/schedule
#(st/emit! (msg/show {:content "Internal Assertion Error"
#(st/emit! (ntf/show {:content "Internal Assertion Error"
:notification-type :toast
:type :error
:timeout 3000})))
@ -154,7 +154,7 @@
[error]
(ts/schedule
#(st/emit!
(msg/show {:content "Something wrong has happened (on worker)."
(ntf/show {:content "Something wrong has happened (on worker)."
:notification-type :toast
:type :error
:timeout 3000})))
@ -168,7 +168,7 @@
(defmethod ptk/handle-error :svg-parser
[_]
(ts/schedule
#(st/emit! (msg/show {:content "SVG is invalid or malformed"
#(st/emit! (ntf/show {:content "SVG is invalid or malformed"
:notification-type :toast
:type :error
:timeout 3000}))))
@ -177,7 +177,7 @@
(defmethod ptk/handle-error :comment-error
[_]
(ts/schedule
#(st/emit! (msg/show {:content "There was an error with the comment"
#(st/emit! (ntf/show {:content "There was an error with the comment"
:notification-type :toast
:type :error
:timeout 3000}))))

View file

@ -24,9 +24,6 @@
(def router
(l/derived :router st/state))
(def message
(l/derived :message st/state))
(def profile
(l/derived :profile st/state))

View file

@ -14,7 +14,7 @@
[app.main.ui.debug.icons-preview :refer [icons-preview]]
[app.main.ui.frame-preview :as frame-preview]
[app.main.ui.icons :as i]
[app.main.ui.messages :as msgs]
[app.main.ui.notifications :as notifications]
[app.main.ui.onboarding.newsletter :refer [onboarding-newsletter]]
[app.main.ui.onboarding.questions :refer [questions-modal]]
[app.main.ui.onboarding.team-choice :refer [onboarding-team-modal]]
@ -194,6 +194,6 @@
(if edata
[:& static/exception-page {:data edata :route route}]
[:*
[:& msgs/notifications-hub]
[:& notifications/current-notification]
(when route
[:& main-page {:route route :profile profile}])])]]))

View file

@ -10,7 +10,7 @@
[app.common.logging :as log]
[app.common.schema :as sm]
[app.config :as cf]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.repo :as rp]
[app.main.store :as st]
@ -37,7 +37,7 @@
{::mf/props :obj}
[]
[:& context-notification
{:type :warning
{:level :warning
:content (tr "auth.demo-warning")}])
(defn create-demo-profile
@ -57,10 +57,10 @@
(cond
(and (= type :restriction)
(= code :provider-not-configured))
(st/emit! (msg/error (tr "errors.auth-provider-not-configured")))
(st/emit! (ntf/error (tr "errors.auth-provider-not-configured")))
:else
(st/emit! (msg/error (tr "errors.generic"))))))))
(st/emit! (ntf/error (tr "errors.generic"))))))))
(def ^:private schema:login-form
[:map {:title "LoginForm"}
@ -86,7 +86,7 @@
(and (= :restriction (:type cause))
(= :ldap-not-initialized (:code cause)))
(st/emit! (msg/error (tr "errors.ldap-disabled")))
(st/emit! (ntf/error (tr "errors.ldap-disabled")))
(and (= :restriction (:type cause))
(= :admin-only-profile (:code cause)))
@ -145,9 +145,8 @@
[:*
(when-let [message @error]
[:& context-notification
{:type :error
{:level :error
:content message
:data-testid "login-banner"
:role "alert"}])
[:& fm/form {:on-submit on-submit

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
@ -29,11 +29,11 @@
(defn- on-error
[_form _error]
(st/emit! (msg/error (tr "errors.invalid-recovery-token"))))
(st/emit! (ntf/error (tr "errors.invalid-recovery-token"))))
(defn- on-success
[_]
(st/emit! (msg/info (tr "auth.notifications.password-changed-successfully"))
(st/emit! (ntf/info (tr "auth.notifications.password-changed-successfully"))
(rt/nav :auth-login)))
(defn- on-submit

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
@ -30,7 +30,7 @@
default-success-finish
(mf/use-fn
#(st/emit! (msg/info (tr "auth.notifications.recovery-token-sent"))))
#(st/emit! (ntf/info (tr "auth.notifications.recovery-token-sent"))))
on-success
(mf/use-fn
@ -47,14 +47,14 @@
(let [code (-> cause ex-data :code)]
(case code
:profile-not-verified
(rx/of (msg/error (tr "auth.notifications.profile-not-verified")))
(rx/of (ntf/error (tr "auth.notifications.profile-not-verified")))
:profile-is-muted
(rx/of (msg/error (tr "errors.profile-is-muted")))
(rx/of (ntf/error (tr "errors.profile-is-muted")))
(:email-has-permanent-bounces
:email-has-complaints)
(rx/of (msg/error (tr "errors.email-has-permanent-bounces" (:email data))))
(rx/of (ntf/error (tr "errors.email-has-permanent-bounces" (:email data))))
(rx/throw cause)))))

View file

@ -9,7 +9,7 @@
(:require
[app.common.schema :as sm]
[app.config :as cf]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.repo :as rp]
[app.main.store :as st]
@ -46,22 +46,22 @@
(let [{:keys [type code] :as edata} (ex-data cause)]
(condp = [type code]
[:restriction :registration-disabled]
(st/emit! (msg/error (tr "errors.registration-disabled")))
(st/emit! (ntf/error (tr "errors.registration-disabled")))
[:restriction :email-domain-is-not-allowed]
(st/emit! (msg/error (tr "errors.email-domain-not-allowed")))
(st/emit! (ntf/error (tr "errors.email-domain-not-allowed")))
[:restriction :email-has-permanent-bounces]
(st/emit! (msg/error (tr "errors.email-has-permanent-bounces" (:email edata))))
(st/emit! (ntf/error (tr "errors.email-has-permanent-bounces" (:email edata))))
[:restriction :email-has-complaints]
(st/emit! (msg/error (tr "errors.email-has-permanent-bounces" (:email edata))))
(st/emit! (ntf/error (tr "errors.email-has-permanent-bounces" (:email edata))))
[:validation :email-as-password]
(swap! form assoc-in [:errors :password]
{:code "errors.email-as-password"})
(st/emit! (msg/error (tr "errors.generic")))))))
(st/emit! (ntf/error (tr "errors.generic")))))))
on-submit
(mf/use-fn
@ -198,7 +198,7 @@
on-error
(mf/use-fn
(fn [_]
(st/emit! (msg/error (tr "errors.generic")))))
(st/emit! (ntf/error (tr "errors.generic")))))
on-submit
(mf/use-fn

View file

@ -6,7 +6,7 @@
(ns app.main.ui.auth.verify-token
(:require
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.repo :as rp]
[app.main.store :as st]
@ -24,13 +24,13 @@
(defmethod handle-token :verify-email
[data]
(let [msg (tr "dashboard.notifications.email-verified-successfully")]
(ts/schedule 1000 #(st/emit! (msg/success msg)))
(ts/schedule 1000 #(st/emit! (ntf/success msg)))
(st/emit! (du/login-from-token data))))
(defmethod handle-token :change-email
[_data]
(let [msg (tr "dashboard.notifications.email-changed-successfully")]
(ts/schedule 100 #(st/emit! (msg/success msg)))
(ts/schedule 100 #(st/emit! (ntf/success msg)))
(st/emit! (rt/nav :settings-profile)
(du/fetch-profile))))
@ -43,7 +43,7 @@
(case (:state tdata)
:created
(st/emit!
(msg/success (tr "auth.notifications.team-invitation-accepted"))
(ntf/success (tr "auth.notifications.team-invitation-accepted"))
(du/fetch-profile)
(rt/nav :dashboard-projects {:team-id (:team-id tdata)}))
@ -56,7 +56,7 @@
[_tdata]
(st/emit!
(rt/nav :auth-login)
(msg/warn (tr "errors.unexpected-token"))))
(ntf/warn (tr "errors.unexpected-token"))))
(mf/defc verify-token
[{:keys [route] :as props}]
@ -79,17 +79,17 @@
(= :email-already-exists code)
(let [msg (tr "errors.email-already-exists")]
(ts/schedule 100 #(st/emit! (msg/error msg)))
(ts/schedule 100 #(st/emit! (ntf/error msg)))
(st/emit! (rt/nav :auth-login)))
(= :email-already-validated code)
(let [msg (tr "errors.email-already-validated")]
(ts/schedule 100 #(st/emit! (msg/warn msg)))
(ts/schedule 100 #(st/emit! (ntf/warn msg)))
(st/emit! (rt/nav :auth-login)))
:else
(let [msg (tr "errors.generic")]
(ts/schedule 100 #(st/emit! (msg/error msg)))
(ts/schedule 100 #(st/emit! (ntf/error msg)))
(st/emit! (rt/nav :auth-login)))))))))
(if @bad-token

View file

@ -9,8 +9,8 @@
[app.main.data.common :as dcm]
[app.main.data.dashboard :as dd]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.repo :as rp]
[app.main.store :as st]
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
@ -88,12 +88,12 @@
on-duplicate
(fn [_]
(apply st/emit! (map dd/duplicate-file files))
(st/emit! (msg/success (tr "dashboard.success-duplicate-file" (i18n/c (count files))))))
(st/emit! (ntf/success (tr "dashboard.success-duplicate-file" (i18n/c (count files))))))
on-delete-accept
(fn [_]
(apply st/emit! (map dd/delete-file files))
(st/emit! (msg/success (tr "dashboard.success-delete-file" (i18n/c (count files))))
(st/emit! (ntf/success (tr "dashboard.success-delete-file" (i18n/c (count files))))
(dd/clear-selected-files)))
on-delete
@ -126,8 +126,8 @@
on-move-success
(fn [team-id project-id]
(if multi?
(st/emit! (msg/success (tr "dashboard.success-move-files")))
(st/emit! (msg/success (tr "dashboard.success-move-file"))))
(st/emit! (ntf/success (tr "dashboard.success-move-files")))
(st/emit! (ntf/success (tr "dashboard.success-move-file"))))
(if (or navigate? (not= team-id current-team-id))
(st/emit! (dd/go-to-files team-id project-id))
(st/emit! (dd/fetch-recent-files team-id)

View file

@ -180,12 +180,12 @@
:on-selected on-selected}]]
[:& context-notification {:content (tr "dashboard.fonts.hero-text2")
:type :default
:level :default
:is-html true}]
(when problematic-fonts?
[:& context-notification {:content (tr "dashboard.fonts.warning-text")
:type :warning
:level :warning
:is-html true}])]]
[:*

View file

@ -13,7 +13,7 @@
[app.common.logging :as log]
[app.config :as cf]
[app.main.data.dashboard :as dd]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.features :as features]
[app.main.fonts :as fonts]
[app.main.rasterizer :as thr]
@ -560,7 +560,7 @@
on-drop-success
(fn []
(st/emit! (msg/success (tr "dashboard.success-move-file"))
(st/emit! (ntf/success (tr "dashboard.success-move-file"))
(dd/fetch-recent-files (:id team))
(dd/clear-selected-files)))

View file

@ -12,8 +12,8 @@
[app.common.logging :as log]
[app.main.data.dashboard :as dd]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.errors :as errors]
[app.main.features :as features]
[app.main.store :as st]
@ -366,7 +366,7 @@
(reset! template-finished* true)
(errors/print-error! cause)
(rx/of (modal/hide)
(msg/error (tr "dashboard.libraries-and-templates.import-error")))))
(ntf/error (tr "dashboard.libraries-and-templates.import-error")))))
continue-entries
(mf/use-fn
@ -481,19 +481,19 @@
[:div {:class (stl/css :modal-content)}
(when (and (= :analyzing status) errors?)
[:& context-notification
{:type :warning
{:level :warning
:content (tr "dashboard.import.import-warning")}])
(when (and (= :importing status) (not ^boolean pending-import?))
(cond
errors?
[:& context-notification
{:type :warning
{:level :warning
:content (tr "dashboard.import.import-warning")}]
:else
[:& context-notification
{:type (if (zero? success-num) :warning :success)
{:level (if (zero? success-num) :warning :success)
:content (tr "dashboard.import.import-message" (i18n/c success-num))}]))
(for [entry entries]

View file

@ -7,8 +7,8 @@
(ns app.main.ui.dashboard.project-menu
(:require
[app.main.data.dashboard :as dd]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
@ -30,7 +30,7 @@
on-duplicate-success
(fn [new-project]
(st/emit! (msg/success (tr "dashboard.success-duplicate-project"))
(st/emit! (ntf/success (tr "dashboard.success-duplicate-project"))
(rt/nav :dashboard-files
{:team-id (:team-id new-project)
:project-id (:id new-project)})))
@ -51,12 +51,12 @@
(fn [team-id]
(let [data {:id (:id project) :team-id team-id}
mdata {:on-success #(on-move-success team-id)}]
#(st/emit! (msg/success (tr "dashboard.success-move-project"))
#(st/emit! (ntf/success (tr "dashboard.success-move-project"))
(dd/move-project (with-meta data mdata)))))
delete-fn
(fn [_]
(st/emit! (msg/success (tr "dashboard.success-delete-project"))
(st/emit! (ntf/success (tr "dashboard.success-delete-project"))
(dd/delete-project project)
(dd/go-to-projects (:team-id project))))

View file

@ -13,8 +13,8 @@
[app.config :as cf]
[app.main.data.dashboard :as dd]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.refs :as refs]
[app.main.store :as st]
@ -149,7 +149,7 @@
on-drop-success
(mf/use-fn
(mf/deps (:id item))
#(st/emit! (msg/success (tr "dashboard.success-move-file"))
#(st/emit! (ntf/success (tr "dashboard.success-move-file"))
(dd/go-to-files (:id item))))
on-drop
@ -362,13 +362,13 @@
(fn [{:keys [code] :as error}]
(condp = code
:no-enough-members-for-leave
(rx/of (msg/error (tr "errors.team-leave.insufficient-members")))
(rx/of (ntf/error (tr "errors.team-leave.insufficient-members")))
:member-does-not-exist
(rx/of (msg/error (tr "errors.team-leave.member-does-not-exists")))
(rx/of (ntf/error (tr "errors.team-leave.member-does-not-exists")))
:owner-cant-leave-team
(rx/of (msg/error (tr "errors.team-leave.owner-cant-leave")))
(rx/of (ntf/error (tr "errors.team-leave.owner-cant-leave")))
(rx/throw error)))

View file

@ -14,8 +14,8 @@
[app.config :as cfg]
[app.main.data.dashboard :as dd]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.refs :as refs]
[app.main.store :as st]
@ -162,7 +162,7 @@
on-success
(fn [_form {:keys [total]}]
(when (pos? total)
(st/emit! (msg/success (tr "notifications.invitation-email-sent"))))
(st/emit! (ntf/success (tr "notifications.invitation-email-sent"))))
(st/emit! (modal/hide)
(dd/fetch-team-invitations)))
@ -173,7 +173,7 @@
(cond
(and (= :validation type)
(= :profile-is-muted code))
(st/emit! (msg/error (tr "errors.profile-is-muted"))
(st/emit! (ntf/error (tr "errors.profile-is-muted"))
(modal/hide))
(or (= :member-is-muted code)
@ -182,7 +182,7 @@
(swap! error-text (tr "errors.email-spam-or-permanent-bounces" (:email error)))
:else
(st/emit! (msg/error (tr "errors.generic"))
(st/emit! (ntf/error (tr "errors.generic"))
(modal/hide)))))
on-submit
@ -203,11 +203,11 @@
(when-not (= "" @error-text)
[:& context-notification {:content @error-text
:type :error}])
:level :error}])
(when (some current-data-emails current-members-emails)
[:& context-notification {:content (tr "modals.invite-member.repeated-invitation")
:type :warning}])
:level :warning}])
[:div {:class (stl/css :role-select)}
[:p {:class (stl/css :role-title)}
@ -368,13 +368,13 @@
(condp = code
:no-enough-members-for-leave
(rx/of (msg/error (tr "errors.team-leave.insufficient-members")))
(rx/of (ntf/error (tr "errors.team-leave.insufficient-members")))
:member-does-not-exist
(rx/of (msg/error (tr "errors.team-leave.member-does-not-exists")))
(rx/of (ntf/error (tr "errors.team-leave.member-does-not-exists")))
:owner-cant-leave-team
(rx/of (msg/error (tr "errors.team-leave.owner-cant-leave")))
(rx/of (ntf/error (tr "errors.team-leave.owner-cant-leave")))
(rx/throw error))))
@ -580,16 +580,16 @@
(cond
(and (= :validation type)
(= :profile-is-muted code))
(rx/of (msg/error (tr "errors.profile-is-muted")))
(rx/of (ntf/error (tr "errors.profile-is-muted")))
(and (= :validation type)
(= :member-is-muted code))
(rx/of (msg/error (tr "errors.member-is-muted")))
(rx/of (ntf/error (tr "errors.member-is-muted")))
(and (= :restriction type)
(or (= :email-has-permanent-bounces code)
(= :email-has-complaints code)))
(rx/of (msg/error (tr "errors.email-has-permanent-bounces" email)))
(rx/of (ntf/error (tr "errors.email-has-permanent-bounces" email)))
:else
(rx/throw cause)))))
@ -605,7 +605,7 @@
on-resend-success
(mf/use-fn
(fn []
(st/emit! (msg/success (tr "notifications.invitation-email-sent"))
(st/emit! (ntf/success (tr "notifications.invitation-email-sent"))
(modal/hide)
(dd/fetch-team-invitations))))
@ -626,7 +626,7 @@
on-copy-success
(mf/use-fn
(fn []
(st/emit! (msg/success (tr "notifications.invitation-link-copied"))
(st/emit! (ntf/success (tr "notifications.invitation-link-copied"))
(modal/hide))))
on-copy
@ -788,7 +788,7 @@
(fn [_]
(let [message (tr "dashboard.webhooks.create.success")]
(st/emit! (dd/fetch-team-webhooks)
(msg/success message)
(ntf/success message)
(modal/hide)))))
on-error

View file

@ -10,8 +10,8 @@
[app.common.schema :as sm]
[app.main.data.dashboard :as dd]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
[app.main.ui.icons :as i]
@ -29,22 +29,22 @@
(defn- on-create-success
[_form response]
(let [msg "Team created successfully"]
(st/emit! (msg/success msg)
(st/emit! (ntf/success msg)
(modal/hide)
(rt/nav :dashboard-projects {:team-id (:id response)}))))
(defn- on-update-success
[_form _response]
(let [msg "Team created successfully"]
(st/emit! (msg/success msg)
(st/emit! (ntf/success msg)
(modal/hide))))
(defn- on-error
[form _response]
(let [id (get-in @form [:clean-data :id])]
(if id
(rx/of (msg/error "Error on updating team."))
(rx/of (msg/error "Error on creating team.")))))
(rx/of (ntf/error "Error on updating team."))
(rx/of (ntf/error "Error on creating team.")))))
(defn- on-create-submit
[form]

View file

@ -1,54 +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) KALEIDOS INC
(ns app.main.ui.messages
(:require
[app.main.data.messages :as dmsg]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.notifications.context-notification :refer [context-notification]]
[app.main.ui.notifications.inline-notification :refer [inline-notification]]
[app.main.ui.notifications.toast-notification :refer [toast-notification]]
[rumext.v2 :as mf]))
(mf/defc notifications-hub
[]
(let [message (mf/deref refs/message)
on-close (mf/use-fn #(st/emit! dmsg/hide))
context? (and (nil? (:timeout message))
(nil? (:actions message)))
inline? (or (= :inline (:notification-type message))
(= :floating (:position message)))
toast? (or (= :toast (:notification-type message))
(some? (:timeout message)))]
(when message
(cond
toast?
[:& toast-notification
{:type (or (:type message) :info)
:links (:links message)
:on-close on-close
:content (:content message)}]
inline?
[:& inline-notification
{:actions (:actions message)
:links (:links message)
:content (:content message)}]
context?
[:& context-notification
{:type (or (:type message) :info)
:links (:links message)
:content (:content message)}]
:else
[:& toast-notification
{:type (or (:type message) :info)
:links (:links message)
:on-close on-close
:content (:content message)}]))))

View file

@ -0,0 +1,57 @@
;; 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) KALEIDOS INC
(ns app.main.ui.notifications
(:require
[app.main.data.notifications :as ntf]
[app.main.store :as st]
[app.main.ui.notifications.context-notification :refer [context-notification]]
[app.main.ui.notifications.inline-notification :refer [inline-notification]]
[app.main.ui.notifications.toast-notification :refer [toast-notification]]
[okulary.core :as l]
[rumext.v2 :as mf]))
(def ref:notification
(l/derived :notification st/state))
(mf/defc current-notification
[]
(let [notification (mf/deref ref:notification)
on-close (mf/use-fn #(st/emit! (ntf/hide)))
context? (and (nil? (:timeout notification))
(nil? (:actions notification)))
inline? (or (= :inline (:type notification))
(= :floating (:position notification)))
toast? (or (= :toast (:type notification))
(some? (:timeout notification)))]
(when notification
(cond
toast?
[:& toast-notification
{:level (or (:level notification) :info)
:links (:links notification)
:on-close on-close
:content (:content notification)}]
inline?
[:& inline-notification
{:actions (:actions notification)
:links (:links notification)
:content (:content notification)}]
context?
[:& context-notification
{:level (or (:level notification) :info)
:links (:links notification)
:content (:content notification)}]
:else
[:& toast-notification
{:level (or (:level notification) :info)
:links (:links notification)
:on-close on-close
:content (:content notification)}]))))

View file

@ -25,9 +25,9 @@
(def ^:private info-icon
(i/icon-xref :help (stl/css :icon)))
(defn get-icon-by-type
[type]
(case type
(defn get-icon-by-level
[level]
(case level
:warning neutral-icon
:error error-icon
:success success-icon
@ -36,19 +36,17 @@
(mf/defc context-notification
"They are persistent, informative and non-actionable.
They are contextual messages in specific areas off the app"
They are contextual messages in specific areas off the app"
{::mf/props :obj}
[{:keys [type content links is-html] :as props}]
[{:keys [level content links is-html] :as props}]
[:aside {:class (stl/css-case :context-notification true
:contain-html is-html
:warning (= type :warning)
:error (= type :error)
:success (= type :success)
:info (= type :info))}
:warning (= level :warning)
:error (= level :error)
:success (= level :success)
:info (= level :info))}
(get-icon-by-type type)
(get-icon-by-level level)
;; The content can arrive in markdown format, in these cases
;; we will use the prop is-html to true to indicate it and

View file

@ -28,9 +28,9 @@
(def ^:private close-icon
(i/icon-xref :close (stl/css :close-icon)))
(defn get-icon-by-type
[type]
(case type
(defn get-icon-by-level
[level]
(case level
:warning neutral-icon
:error error-icon
:success success-icon
@ -44,15 +44,15 @@
error messages that require user interaction."
{::mf/props :obj}
[{:keys [type content on-close links] :as props}]
[{:keys [level content on-close links] :as props}]
[:aside {:class (stl/css-case :toast-notification true
:warning (= type :warning)
:error (= type :error)
:success (= type :success)
:info (= type :info))}
:warning (= level :warning)
:error (= level :error)
:success (= level :success)
:info (= level :info))}
(get-icon-by-type type)
(get-icon-by-level level)
[:div {:class (stl/css :text)}
content

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl])
(:require
[app.main.data.events :as-alias ev]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.icons :as i]
@ -37,7 +37,7 @@
(fn []
(when (or (:newsletter-updates state)
(:newsletter-news state))
(st/emit! (msg/success (tr "onboarding.newsletter.acceptance-message"))))
(st/emit! (ntf/success (tr "onboarding.newsletter.acceptance-message"))))
(let [params (-> state
(assoc ::ev/name "onboarding-step")

View file

@ -11,7 +11,7 @@
[app.common.schema :as sm]
[app.main.data.dashboard :as dd]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
@ -90,7 +90,7 @@
on-error
(mf/use-fn
(fn [_]
(st/emit! (msg/error (tr "errors.generic")))))
(st/emit! (ntf/error (tr "errors.generic")))))
on-invite-later
(mf/use-fn

View file

@ -8,8 +8,8 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
@ -64,7 +64,7 @@
(fn [_]
(let [message (tr "dashboard.access-tokens.create.success")]
(st/emit! (du/fetch-access-tokens)
(msg/success message)
(ntf/success message)
(reset! created? true)))))
on-close
@ -77,7 +77,7 @@
on-error
(mf/use-fn
(fn [_]
(st/emit! (msg/error (tr "errors.generic"))
(st/emit! (ntf/error (tr "errors.generic"))
(modal/hide))))
on-submit
@ -99,7 +99,7 @@
(fn [event]
(dom/prevent-default event)
(wapi/write-to-clipboard (:token created))
(st/emit! (msg/show {:type :info
(st/emit! (ntf/show {:type :info
:notification-type :toast
:content (tr "dashboard.access-tokens.copied-success")
:timeout 7000}))))]

View file

@ -8,8 +8,8 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.refs :as refs]
[app.main.store :as st]
@ -30,11 +30,11 @@
(assoc-in data [:errors :email-1] error))))
:profile-is-muted
(rx/of (msg/error (tr "errors.profile-is-muted")))
(rx/of (ntf/error (tr "errors.profile-is-muted")))
(:email-has-permanent-bounces
:email-has-complaints)
(rx/of (msg/error (tr "errors.email-has-permanent-bounces" (:email error))))
(rx/of (ntf/error (tr "errors.email-has-permanent-bounces" (:email error))))
(rx/throw cause))))
@ -44,7 +44,7 @@
(st/emit! (du/fetch-profile)
(modal/hide))
(let [message (tr "notifications.validation-email-sent" (:email profile))]
(st/emit! (msg/info message)
(st/emit! (ntf/info message)
(modal/hide)))))
(defn- on-submit
@ -95,7 +95,7 @@
[:div {:class (stl/css :modal-content)}
[:& context-notification
{:type :info
{:level :info
:content (tr "modals.change-email.info" (:email profile))}]
[:div {:class (stl/css :fields-row)}

View file

@ -7,8 +7,8 @@
(ns app.main.ui.settings.delete-account
(:require-macros [app.main.style :as stl])
(:require
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.icons :as i]
@ -22,7 +22,7 @@
(let [code (-> cause ex-data :code)]
(if (= :owner-teams-with-people code)
(let [msg (tr "notifications.profile-deletion-not-allowed")]
(rx/of (msg/error msg)))
(rx/of (ntf/error msg)))
(rx/throw cause))))
(mf/defc delete-account-modal
@ -49,7 +49,7 @@
[:div {:class (stl/css :modal-content)}
[:& context-notification
{:type :warning
{:level :warning
:content (tr "modals.delete-account.info")}]]
[:div {:class (stl/css :modal-footer)}

View file

@ -9,7 +9,7 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.refs :as refs]
[app.main.repo :as rp]
[app.main.store :as st]
@ -36,7 +36,7 @@
(mf/deps profile)
(fn [_]
(reset! loading false)
(st/emit! (msg/success (tr "labels.feedback-sent")))
(st/emit! (ntf/success (tr "labels.feedback-sent")))
(swap! form assoc :data {} :touched {} :errors {})))
on-error
@ -45,8 +45,8 @@
(fn [{:keys [code] :as error}]
(reset! loading false)
(if (= code :feedback-disabled)
(st/emit! (msg/error (tr "labels.feedback-disabled")))
(st/emit! (msg/error (tr "errors.generic"))))))
(st/emit! (ntf/error (tr "labels.feedback-disabled")))
(st/emit! (ntf/error (tr "errors.generic"))))))
on-submit
(mf/use-fn

View file

@ -7,7 +7,7 @@
(ns app.main.ui.settings.options
(:require-macros [app.main.style :as stl])
(:require
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.refs :as refs]
[app.main.store :as st]
@ -23,7 +23,7 @@
(defn- on-success
[profile]
(st/emit! (msg/success (tr "notifications.profile-saved"))
(st/emit! (ntf/success (tr "notifications.profile-saved"))
(du/profile-fetched profile)))
(defn- on-submit

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.notifications :as ntf]
[app.main.data.users :as udu]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
@ -27,7 +27,7 @@
{:code "errors.email-as-password"})
(let [msg (tr "generic.error")]
(st/emit! (msg/error msg)))))
(st/emit! (ntf/error msg)))))
(defn- on-success
[form]
@ -36,7 +36,7 @@
msg (tr "dashboard.notifications.password-saved")]
(dom/clean-value! password-old-node)
(dom/focus! password-old-node)
(st/emit! (msg/success msg))))
(st/emit! (ntf/success msg))))
(defn- on-submit
[form event]

View file

@ -9,8 +9,8 @@
(:require
[app.common.schema :as sm]
[app.config :as cf]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.users :as du]
[app.main.refs :as refs]
[app.main.store :as st]
@ -30,7 +30,7 @@
(let [data (:clean-data @form)]
(st/emit! (du/update-profile data)
(du/persist-profile)
(msg/success (tr "notifications.profile-saved")))))
(ntf/success (tr "notifications.profile-saved")))))
;; --- Profile Form

View file

@ -13,8 +13,8 @@
[app.config :as cf]
[app.main.data.common :as dc]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.select :refer [select]]
@ -134,7 +134,7 @@
copy-link
(fn [_]
(wapi/write-to-clipboard current-link)
(st/emit! (msg/show {:type :info
(st/emit! (ntf/show {:type :info
:notification-type :toast
:content (tr "common.share-link.link-copied-success")
:timeout 1000})))

View file

@ -8,8 +8,8 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.persistence :as dps]
[app.main.data.workspace :as dw]
[app.main.data.workspace.colors :as dc]
@ -195,7 +195,7 @@
(st/emit! ::dps/force-persist
(dc/stop-picker)
(modal/hide)
msg/hide
(ntf/hide)
(dw/finalize-file project-id file-id))))
[:& (mf/provider ctx/current-file-id) {:value file-id}