diff --git a/backend/src/app/srepl/main.clj b/backend/src/app/srepl/main.clj index be5c9e57db..6914ff54dd 100644 --- a/backend/src/app/srepl/main.clj +++ b/backend/src/app/srepl/main.clj @@ -209,100 +209,116 @@ 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}] + The destination can be: all, profile-id, team-id, or a coll of them. + It also can be: + + {:email \"some@example.com\"} + [[:email \"some@example.com\"], ...] + + Command examples: + + (notify! :dest :all :code :maintenance) + (notify! :dest :all :code :upgrade-version) + " + [& {:keys [dest code message level] + :or {code :generic level :info} + :as params}] (when-not (contains? #{:success :error :info :warning} level) (ex/raise :type :assertion :code :incorrect-level :hint (str "level '" level "' not supported"))) - (letfn [(send [dest] - (l/inf :hint "sending notification" :dest (str dest)) - (let [message {:type :notification - :code code - :level level - :version (:full cf/version) - :subs-id dest - :message message} - message (->> (dissoc params :dest :code :message :level) - (merge message))] - (mbus/pub! msgbus - :topic (str dest) - :message message))) + (let [{:keys [::mbus/msgbus ::db/pool]} main/system - (resolve-profile [email] - (some-> (db/get* pool :profile {:email (str/lower email)} {:columns [:id]}) :id vector)) + send + (fn [dest] + (l/inf :hint "sending notification" :dest (str dest)) + (let [message {:type :notification + :code code + :level level + :version (:full cf/version) + :subs-id dest + :message message} + message (->> (dissoc params :dest :code :message :level) + (merge message))] + (mbus/pub! msgbus + :topic dest + :message message))) - (resolve-team [team-id] - (->> (db/query pool :team-profile-rel - {:team-id team-id} - {:columns [:profile-id]}) - (map :profile-id))) + resolve-profile + (fn [email] + (some-> (db/get* pool :profile {:email (str/lower email)} {:columns [:id]}) :id vector)) - (resolve-dest [dest] - (cond - (= :all dest) - [uuid/zero] + resolve-team + (fn [team-id] + (->> (db/query pool :team-profile-rel + {:team-id team-id} + {:columns [:profile-id]}) + (map :profile-id))) - (uuid? dest) - [dest] + resolve-dest + (fn resolve-dest [dest] + (cond + (= :all dest) + [uuid/zero] - (string? dest) - (some-> dest h/parse-uuid resolve-dest) + (uuid? dest) + [dest] - (nil? dest) - (resolve-dest uuid/zero) + (string? dest) + (some-> dest h/parse-uuid resolve-dest) - (map? dest) - (sequence (comp - (map vec) - (mapcat resolve-dest)) - dest) + (nil? dest) + [uuid/zero] - (and (vector? dest) - (every? vector? dest)) - (sequence (comp - (map vec) - (mapcat resolve-dest)) - dest) + (map? dest) + (sequence (comp + (map vec) + (mapcat resolve-dest)) + dest) - (and (vector? dest) - (keyword? (first dest))) - (let [[op param] dest] + (and (vector? dest) + (every? vector? dest)) + (sequence (comp + (map vec) + (mapcat resolve-dest)) + dest) + + (and (vector? dest) + (keyword? (first dest))) + (let [[op param] dest] + (cond + (= op :email) (cond - (= op :email) - (cond - (and (coll? param) - (every? string? param)) - (sequence (comp - (keep resolve-profile) - (mapcat identity)) - param) + (and (coll? param) + (every? string? param)) + (sequence (comp + (keep resolve-profile) + (mapcat identity)) + param) - (string? param) - (resolve-profile param)) + (string? param) + (resolve-profile param)) - (= op :team-id) - (cond - (coll? param) - (sequence (comp - (mapcat resolve-team) - (keep h/parse-uuid)) - param) + (= op :team-id) + (cond + (coll? param) + (sequence (comp + (mapcat resolve-team) + (keep h/parse-uuid)) + param) - (uuid? param) - (resolve-team param) + (uuid? param) + (resolve-team param) - (string? param) - (some-> param h/parse-uuid resolve-team)) + (string? param) + (some-> param h/parse-uuid resolve-team)) - (= op :profile-id) - (if (coll? param) - (sequence (keep h/parse-uuid) param) - (resolve-dest param))))))] + (= op :profile-id) + (if (coll? param) + (sequence (keep h/parse-uuid) param) + (resolve-dest param))))))] (->> (resolve-dest dest) (filter some?) diff --git a/frontend/src/app/main/data/common.cljs b/frontend/src/app/main/data/common.cljs index 064d1901d5..713c5d1989 100644 --- a/frontend/src/app/main/data/common.cljs +++ b/frontend/src/app/main/data/common.cljs @@ -73,7 +73,7 @@ (st/emit! (ntf/hide))) (defn handle-notification - [{:keys [message code level] :as params}] + [{:keys [message code] :as params}] (ptk/reify ::show-notification ptk/WatchEvent (watch [_ _ _] @@ -81,9 +81,6 @@ :upgrade-version (rx/of (ntf/dialog :content (tr "notifications.by-code.upgrade-version") - :controls :inline-actions - :type :inline - :level level :accept {:label (tr "labels.refresh") :callback force-reload!} :tag :notification)) @@ -91,16 +88,14 @@ :maintenance (rx/of (ntf/dialog :content (tr "notifications.by-code.maintenance") - :controls :inline-actions - :type level :accept {:label (tr "labels.accept") :callback hide-notifications!} :tag :notification)) (rx/of (ntf/dialog :content message - :controls :close - :type level + :accept {:label (tr "labels.close") + :callback hide-notifications!} :tag :notification)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/frontend/src/app/main/data/notifications.cljs b/frontend/src/app/main/data/notifications.cljs index 37caee0ba2..5c0082bec3 100644 --- a/frontend/src/app/main/data/notifications.cljs +++ b/frontend/src/app/main/data/notifications.cljs @@ -19,7 +19,7 @@ (def ^:private schema:notification [:map {:title "Notification"} - [:level [::sm/one-of #{:success :error :info :warning}]] + [:level {:optional true} [::sm/one-of #{:success :error :info :warning}]] [:status {:optional true} [::sm/one-of #{:visible :hide}]] [:position {:optional true} @@ -129,15 +129,11 @@ :timeout timeout}))) (defn dialog - [& {:keys [content controls actions accept cancel position tag level links] - :or {controls :none position :floating level :info}}] + [& {:keys [content accept cancel tag links]}] (show (d/without-nils {:content content - :level level - :links links - :position position - :controls controls - :actions actions + :type :inline :accept accept :cancel cancel + :links links :tag tag}))) diff --git a/frontend/src/app/main/data/workspace/notifications.cljs b/frontend/src/app/main/data/workspace/notifications.cljs index e62985f70b..dc46e6e355 100644 --- a/frontend/src/app/main/data/workspace/notifications.cljs +++ b/frontend/src/app/main/data/workspace/notifications.cljs @@ -65,7 +65,6 @@ (->> (rx/from initmsg) (rx/map dws/send)) - ;; Subscribe to notifications of the subscription (->> stream (rx/filter (ptk/type? ::dws/message)) diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index f751232397..f67fb755a3 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -370,6 +370,6 @@ (if edata [:> static/exception-page* {:data edata :route route}] [:> error-boundary* {:fallback static/internal-error*} - [:& notifications/current-notification] + [:> notifications/current-notification*] (when route [:> page* {:route route :profile profile}])])]])) diff --git a/frontend/src/app/main/ui/ds/notifications/actionable.cljs b/frontend/src/app/main/ui/ds/notifications/actionable.cljs index 9284b5387a..550d2a2976 100644 --- a/frontend/src/app/main/ui/ds/notifications/actionable.cljs +++ b/frontend/src/app/main/ui/ds/notifications/actionable.cljs @@ -17,10 +17,10 @@ [:class {:optional true} :string] [:variant {:optional true} [:maybe [:enum "default" "error"]]] - [:accept-label {:optional true} :string] - [:cancel-label {:optional true} :string] - [:on-accept {:optional true} [:fn fn?]] - [:on-cancel {:optional true} [:fn fn?]]]) + [:accept-label {:optional true} [:maybe :string]] + [:cancel-label {:optional true} [:maybe :string]] + [:on-accept {:optional true} [:maybe [:fn fn?]]] + [:on-cancel {:optional true} [:maybe [:fn fn?]]]]) (mf/defc actionable* {::mf/schema schema:actionable} @@ -45,9 +45,13 @@ [:> :aside props [:div {:class (stl/css :notification-message)} children] - [:> button* {:variant "secondary" - :on-click on-cancel} - cancel-label] - [:> button* {:variant (if (= variant "default") "primary" "destructive") - :on-click on-accept} - accept-label]])) + + (when cancel-label + [:> button* {:variant "secondary" + :on-click on-cancel} + cancel-label]) + + (when accept-label + [:> button* {:variant (if (= variant "default") "primary" "destructive") + :on-click on-accept} + accept-label])])) diff --git a/frontend/src/app/main/ui/notifications.cljs b/frontend/src/app/main/ui/notifications.cljs index 5f19792d64..e78ac74944 100644 --- a/frontend/src/app/main/ui/notifications.cljs +++ b/frontend/src/app/main/ui/notifications.cljs @@ -14,10 +14,10 @@ [okulary.core :as l] [rumext.v2 :as mf])) -(def ref:notification +(def ^:private ref:notification (l/derived :notification st/state)) -(mf/defc current-notification +(mf/defc current-notification* [] (let [notification (mf/deref ref:notification) on-close (mf/use-fn #(st/emit! (ntf/hide))) diff --git a/frontend/src/app/util/websocket.cljs b/frontend/src/app/util/websocket.cljs index 016eb9c0ae..5c82ce1948 100644 --- a/frontend/src/app/util/websocket.cljs +++ b/frontend/src/app/util/websocket.cljs @@ -104,7 +104,9 @@ (defn send! [ws msg] - (-send ws (t/encode-str msg))) + (if *assert* + (-send ws (t/encode-str msg {:type :json-verbose})) + (-send ws (t/encode-str msg)))) (defn close! [ws]