mirror of
https://github.com/penpot/penpot.git
synced 2025-04-04 11:01:20 -05:00
Merge pull request #4902 from penpot/niwinz-notifications-improvements
✨ Improvements to notifications
This commit is contained in:
commit
3832377e04
7 changed files with 100 additions and 76 deletions
|
@ -194,6 +194,12 @@
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn notify!
|
||||
"Send flash notifications.
|
||||
|
||||
This method allows send flash notifications to specified target destinations.
|
||||
The message can be a free text or a preconfigured one.
|
||||
|
||||
The destination can be: all, profile-id, team-id, or a coll of them."
|
||||
[{:keys [::mbus/msgbus ::db/pool]} & {:keys [dest code message level]
|
||||
:or {code :generic level :info}
|
||||
:as params}]
|
||||
|
@ -201,10 +207,6 @@
|
|||
["invalid level %" level]
|
||||
(contains? #{:success :error :info :warning} level))
|
||||
|
||||
(dm/verify!
|
||||
["invalid code: %" code]
|
||||
(contains? #{:generic :upgrade-version} code))
|
||||
|
||||
(letfn [(send [dest]
|
||||
(l/inf :hint "sending notification" :dest (str dest))
|
||||
(let [message {:type :notification
|
||||
|
@ -230,6 +232,9 @@
|
|||
|
||||
(resolve-dest [dest]
|
||||
(cond
|
||||
(= :all dest)
|
||||
[uuid/zero]
|
||||
|
||||
(uuid? dest)
|
||||
[dest]
|
||||
|
||||
|
@ -245,14 +250,15 @@
|
|||
(mapcat resolve-dest))
|
||||
dest)
|
||||
|
||||
(and (coll? dest)
|
||||
(every? coll? dest))
|
||||
(and (vector? dest)
|
||||
(every? vector? dest))
|
||||
(sequence (comp
|
||||
(map vec)
|
||||
(mapcat resolve-dest))
|
||||
dest)
|
||||
|
||||
(vector? dest)
|
||||
(and (vector? dest)
|
||||
(keyword? (first dest)))
|
||||
(let [[op param] dest]
|
||||
(cond
|
||||
(= op :email)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.main.data.modal :as modal]
|
||||
[app.main.features :as features]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
@ -58,6 +59,10 @@
|
|||
[]
|
||||
(.reload js/location))
|
||||
|
||||
(defn hide-notifications!
|
||||
[]
|
||||
(st/emit! msg/hide))
|
||||
|
||||
(defn handle-notification
|
||||
[{:keys [message code level] :as params}]
|
||||
(ptk/reify ::show-notification
|
||||
|
@ -75,6 +80,15 @@
|
|||
:actions [{:label "Refresh" :callback force-reload!}]
|
||||
:tag :notification)))
|
||||
|
||||
:maintenance
|
||||
(rx/of (msg/dialog
|
||||
:content (tr "notifications.by-code.maintenance")
|
||||
:controls :inline-actions
|
||||
:type level
|
||||
:actions [{:label (tr "labels.accept")
|
||||
:callback hide-notifications!}]
|
||||
:tag :notification))
|
||||
|
||||
(rx/of (msg/dialog
|
||||
:content message
|
||||
:controls :close
|
||||
|
|
|
@ -15,42 +15,42 @@
|
|||
(declare hide)
|
||||
(declare show)
|
||||
|
||||
(def default-animation-timeout 600)
|
||||
(def default-timeout 7000)
|
||||
|
||||
(def ^:private
|
||||
schema:message
|
||||
(sm/define
|
||||
[:map {:title "Message"}
|
||||
[:type [::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}
|
||||
[::sm/one-of #{:inline :context :toast}]]
|
||||
[:controls {:optional true}
|
||||
[::sm/one-of #{:none :close :inline-actions :bottom-actions}]]
|
||||
[:tag {:optional true}
|
||||
[:or :string :keyword]]
|
||||
[:timeout {:optional true}
|
||||
[:maybe :int]]
|
||||
[:actions {:optional true}
|
||||
[:vector
|
||||
[:map
|
||||
[:label :string]
|
||||
[:callback ::sm/fn]]]]
|
||||
[:links {:optional true}
|
||||
[:vector
|
||||
[:map
|
||||
[:label :string]
|
||||
[:callback ::sm/fn]]]]]))
|
||||
(def ^:private schema:message
|
||||
[:map {:title "Message"}
|
||||
[:type [::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}
|
||||
[::sm/one-of #{:inline :context :toast}]]
|
||||
[:controls {:optional true}
|
||||
[::sm/one-of #{:none :close :inline-actions :bottom-actions}]]
|
||||
[:tag {:optional true}
|
||||
[:or :string :keyword]]
|
||||
[:timeout {:optional true}
|
||||
[:maybe :int]]
|
||||
[:actions {:optional true}
|
||||
[:vector
|
||||
[:map
|
||||
[:label :string]
|
||||
[:callback ::sm/fn]]]]
|
||||
[:links {:optional true}
|
||||
[:vector
|
||||
[:map
|
||||
[:label :string]
|
||||
[:callback ::sm/fn]]]]])
|
||||
|
||||
(def ^:private valid-message?
|
||||
(sm/validator schema:message))
|
||||
|
||||
(defn show
|
||||
[data]
|
||||
(dm/assert!
|
||||
"expected valid message map"
|
||||
(sm/check! schema:message data))
|
||||
(valid-message? data))
|
||||
|
||||
(ptk/reify ::show
|
||||
ptk/UpdateEvent
|
||||
|
@ -76,14 +76,7 @@
|
|||
(ptk/reify ::hide
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(d/update-when state :message assoc :status :hide))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(let [stopper (rx/filter (ptk/type? ::show) stream)]
|
||||
(->> (rx/of #(dissoc % :message))
|
||||
(rx/delay default-animation-timeout)
|
||||
(rx/take-until stopper))))))
|
||||
(dissoc state :message))))
|
||||
|
||||
(defn hide-tag
|
||||
[tag]
|
||||
|
|
|
@ -17,33 +17,38 @@
|
|||
(mf/defc notifications-hub
|
||||
[]
|
||||
(let [message (mf/deref refs/message)
|
||||
|
||||
on-close #(st/emit! dmsg/hide)
|
||||
|
||||
toast-message {:type (or (:type message) :info)
|
||||
:links (:links message)
|
||||
:on-close on-close
|
||||
:content (:content message)}
|
||||
|
||||
inline-message {:actions (:actions message)
|
||||
:links (:links message)
|
||||
:content (:content message)}
|
||||
|
||||
context-message {:type (or (:type message) :info)
|
||||
:links (:links message)
|
||||
:content (:content message)}
|
||||
|
||||
is-context-msg (and (nil? (:timeout message)) (nil? (:actions message)))
|
||||
is-toast-msg (or (= :toast (:notification-type message)) (some? (:timeout message)))
|
||||
is-inline-msg (or (= :inline (:notification-type message)) (and (some? (:position message)) (= :floating (:position 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
|
||||
is-toast-msg
|
||||
[:& toast-notification toast-message]
|
||||
is-inline-msg
|
||||
[:& inline-notification inline-message]
|
||||
is-context-msg
|
||||
[:& context-notification context-message]
|
||||
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 toast-message]))))
|
||||
[:& toast-notification
|
||||
{:type (or (:type message) :info)
|
||||
:links (:links message)
|
||||
:on-close on-close
|
||||
:content (:content message)}]))))
|
||||
|
|
|
@ -38,12 +38,10 @@
|
|||
neutral-icon))
|
||||
|
||||
(mf/defc toast-notification
|
||||
"These are ephemeral elements that disappear when
|
||||
the close button is pressed,
|
||||
the page is refreshed,
|
||||
the page is navigated to another page or
|
||||
after 7 seconds, which is enough time to be read,
|
||||
except for error messages that require user interaction."
|
||||
"These are ephemeral elements that disappear when the close button
|
||||
is pressed, the page is refreshed, the page is navigated to another
|
||||
page or after 7 seconds, which is enough time to be read, except for
|
||||
error messages that require user interaction."
|
||||
|
||||
{::mf/props :obj}
|
||||
[{:keys [type content on-close links] :as props}]
|
||||
|
|
|
@ -2209,6 +2209,10 @@ msgstr "Update a component in a shared library"
|
|||
msgid "notifications.by-code.upgrade-version"
|
||||
msgstr "A new version is available, please refresh the page"
|
||||
|
||||
#: src/app/main/data/common.cljs
|
||||
msgid "notifications.by-code.maintenance"
|
||||
msgstr "Maintenance break: we will be down for a short maintenance within 5 minutes."
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs
|
||||
msgid "notifications.invitation-email-sent"
|
||||
msgstr "Invitation sent successfully"
|
||||
|
|
|
@ -2285,6 +2285,10 @@ msgstr "Actualizar un componente en biblioteca"
|
|||
msgid "notifications.by-code.upgrade-version"
|
||||
msgstr "Una nueva versión está disponible, por favor actualiza la página"
|
||||
|
||||
#: src/app/main/data/common.cljs
|
||||
msgid "notifications.by-code.maintenance"
|
||||
msgstr "Pausa de mantenimiento: en los próximos 5 minutos estaremos fuera de servicio por un breve mantenimiento."
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs
|
||||
msgid "notifications.invitation-email-sent"
|
||||
msgstr "Invitación enviada con éxito"
|
||||
|
|
Loading…
Add table
Reference in a new issue