mirror of
https://github.com/penpot/penpot.git
synced 2025-06-01 15:11:43 +02:00
🐛 Fix problem with error detail in toast (#6259)
This commit is contained in:
parent
82cf474863
commit
28a6797595
10 changed files with 118 additions and 20 deletions
|
@ -8,7 +8,10 @@
|
|||
(:require-macros
|
||||
[app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn icons-by-level
|
||||
|
@ -26,12 +29,14 @@
|
|||
[:level [:enum :default :info :warning :error :success]]
|
||||
[:type [:enum :toast :context]]
|
||||
[:appearance {:optional true} [:enum :neutral :ghost]]
|
||||
[:is-html {:optional true} :boolean]])
|
||||
[:is-html {:optional true} :boolean]
|
||||
[:show-detail {:optional true} [:maybe :boolean]]
|
||||
[:on-toggle-detail {:optional true} [:maybe fn?]]])
|
||||
|
||||
(mf/defc notification-pill*
|
||||
{::mf/props :obj
|
||||
::mf/schema schema:notification-pill}
|
||||
[{:keys [level type is-html appearance children]}]
|
||||
[{:keys [level type is-html appearance detail children show-detail on-toggle-detail]}]
|
||||
(let [class (stl/css-case :notification-pill true
|
||||
:appearance-neutral (= appearance :neutral)
|
||||
:appearance-ghost (= appearance :ghost)
|
||||
|
@ -44,12 +49,27 @@
|
|||
:level-info (= level :info))
|
||||
is-html (or is-html false)
|
||||
icon-id (icons-by-level level)]
|
||||
[:div {:class class}
|
||||
[:> i/icon* {:icon-id icon-id :class (stl/css :icon)}]
|
||||
[:div {:class (dm/str class " " (stl/css :notification-pill))}
|
||||
[:div {:class (stl/css :error-message)}
|
||||
[:> i/icon* {:icon-id icon-id :class (stl/css :icon)}]
|
||||
;; The content can arrive in markdown format, in these cases
|
||||
;; we will use the prop is-html to true to indicate it and
|
||||
;; that the html injection is performed and the necessary css classes are applied.
|
||||
(if is-html
|
||||
[:div {:class (stl/css :context-text)
|
||||
:dangerouslySetInnerHTML #js {:__html children}}]
|
||||
children)]))
|
||||
;; we will use the prop is-html to true to indicate it and
|
||||
;; that the html injection is performed and the necessary css classes are applied.
|
||||
(if is-html
|
||||
[:div {:class (stl/css :context-text)
|
||||
:dangerouslySetInnerHTML #js {:__html children}}]
|
||||
children)]
|
||||
|
||||
(when detail
|
||||
[:div {:class (stl/css :error-detail)}
|
||||
[:div {:class (stl/css :error-detail-title)}
|
||||
[:> icon-button*
|
||||
{:icon (if show-detail "arrow-down" "arrow")
|
||||
:aria-label (tr "workspace.notification-pill.detail")
|
||||
:icon-class (stl/css :expand-icon)
|
||||
:variant "action"
|
||||
:on-click on-toggle-detail}]
|
||||
[:div {:on-click on-toggle-detail}
|
||||
(tr "workspace.notification-pill.detail")]]
|
||||
(when show-detail
|
||||
[:div {:class (stl/css :error-detail-content)} detail])])]))
|
||||
|
|
|
@ -83,3 +83,34 @@
|
|||
color: var(--notification-icon-color);
|
||||
margin-block-start: var(--notification-icon-margin);
|
||||
}
|
||||
|
||||
.notification-pill {
|
||||
display: grid;
|
||||
max-height: 92vh;
|
||||
overflow: hidden;
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
display: flex;
|
||||
gap: var(--sp-s);
|
||||
}
|
||||
|
||||
.error-detail {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.error-detail-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
--icon-fill-color: var(--color-foreground-primary);
|
||||
--icon-stroke-color: var(--color-foreground-primary);
|
||||
}
|
||||
|
||||
.error-detail-content {
|
||||
padding-left: var(--sp-xxxl);
|
||||
}
|
||||
|
|
|
@ -21,12 +21,14 @@
|
|||
[:level {:optional true} [:maybe [:enum :default :info :warning :error :success]]]
|
||||
[:appearance {:optional true} [:enum :neutral :ghost]]
|
||||
[:is-html {:optional true} :boolean]
|
||||
[:on-close {:optional true} fn?]])
|
||||
[:show-detail {:optional true} [:maybe :boolean]]
|
||||
[:on-close {:optional true} fn?]
|
||||
[:on-toggle-detail {:optional true} [:maybe fn?]]])
|
||||
|
||||
(mf/defc toast*
|
||||
{::mf/props :obj
|
||||
::mf/schema schema:toast}
|
||||
[{:keys [class level appearance type is-html children on-close] :rest props}]
|
||||
[{:keys [class level appearance type is-html children detail show-detail on-close on-toggle-detail] :rest props}]
|
||||
(let [class (dm/str class " " (stl/css :toast))
|
||||
level (if (string? level)
|
||||
(keyword level)
|
||||
|
@ -45,9 +47,14 @@
|
|||
[:> notification-pill* {:level level
|
||||
:type type
|
||||
:is-html is-html
|
||||
:appearance appearance} children]
|
||||
;; TODO: this should be a buttom from the DS, but this variant is not designed yet.
|
||||
;; https://tree.taiga.io/project/penpot/task/8492
|
||||
:appearance appearance
|
||||
:detail detail
|
||||
:show-detail show-detail
|
||||
:on-toggle-detail on-toggle-detail} children]
|
||||
|
||||
|
||||
;; TODO: this should be a buttom from the DS, but this variant is not designed yet.
|
||||
;; https://tree.taiga.io/project/penpot/task/8492
|
||||
[:> "button" {:on-click on-close
|
||||
:aria-label "Close"
|
||||
:class (stl/css-case :close-button true
|
||||
|
|
|
@ -17,6 +17,12 @@ export default {
|
|||
children: {
|
||||
control: { type: "text" },
|
||||
},
|
||||
detail: {
|
||||
control: { type: "text" },
|
||||
},
|
||||
showDetail: {
|
||||
control: { type: "boolean" },
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: "Lorem ipsum",
|
||||
|
@ -40,6 +46,14 @@ export const WithLongerText = {
|
|||
},
|
||||
};
|
||||
|
||||
export const WithDetail = {
|
||||
args: {
|
||||
detail:
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent lorem ante, bibendum sed ex.",
|
||||
showDetail: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithHTML = {
|
||||
args: {
|
||||
children:
|
||||
|
|
|
@ -27,7 +27,14 @@
|
|||
(= :floating (:position notification)))
|
||||
toast? (or (= :toast (:type notification))
|
||||
(some? (:timeout notification)))
|
||||
content (or (:content notification) "")]
|
||||
content (or (:content notification) "")
|
||||
|
||||
show-detail* (mf/use-state false)
|
||||
|
||||
handle-toggle-detail
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(swap! show-detail* not)))]
|
||||
|
||||
(when notification
|
||||
(cond
|
||||
|
@ -35,7 +42,10 @@
|
|||
[:> toast*
|
||||
{:level (or (:level notification) :info)
|
||||
:type (:type notification)
|
||||
:on-close on-close} content]
|
||||
:detail (:detail notification)
|
||||
:on-close on-close
|
||||
:show-detail @show-detail*
|
||||
:on-toggle-detail handle-toggle-detail} content]
|
||||
|
||||
inline?
|
||||
[:& inline-notification
|
||||
|
@ -55,4 +65,5 @@
|
|||
[:> toast*
|
||||
{:level (or (:level notification) :info)
|
||||
:type (:type notification)
|
||||
:detail (:detail notification)
|
||||
:on-close on-close} content]))))
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
:error.import/style-dictionary-reference-errors
|
||||
{:error/code :error.import/style-dictionary-reference-errors
|
||||
:error/fn #(str (tr "workspace.token.import-error") "\n\n" (str/join "\n\n" %))}
|
||||
:error/fn #(str (tr "workspace.token.import-error") "\n\n" (first %))
|
||||
:error/detail #(str/join "\n\n" (rest %))}
|
||||
|
||||
:error.import/style-dictionary-unknown-error
|
||||
{:error/code :error.import/style-dictionary-reference-errors
|
||||
|
@ -74,3 +75,9 @@
|
|||
(:error/fn err) ((:error/fn err) (:error/value err))
|
||||
(:error/message err) (:error/message err)
|
||||
:else err)))))
|
||||
|
||||
(defn detail-errors [errors]
|
||||
(->> errors
|
||||
(map (fn [err]
|
||||
(when (:error/detail err)
|
||||
((:error/detail err) (:error/value err)))))))
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
[app.main.data.tokens :as dt]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown-menu :refer [dropdown-menu
|
||||
dropdown-menu-item*]]
|
||||
[app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]]
|
||||
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
|
@ -378,6 +377,7 @@
|
|||
(fn [err]
|
||||
(js/console.error err)
|
||||
(st/emit! (ntf/show {:content (wte/humanize-errors [(ex-data err)])
|
||||
:detail (wte/detail-errors [(ex-data err)])
|
||||
:type :toast
|
||||
:level :error})))))
|
||||
(-> (mf/ref-val input-ref)
|
||||
|
|
|
@ -7272,3 +7272,7 @@ msgstr "Autosaved versions will be kept for %s days."
|
|||
#, unused
|
||||
msgid "workspace.viewport.click-to-close-path"
|
||||
msgstr "Click to close the path"
|
||||
|
||||
msgid "workspace.notification-pill.detail"
|
||||
msgstr "Details"
|
||||
|
||||
|
|
|
@ -7248,3 +7248,6 @@ msgstr "Los autoguardados duran %s días."
|
|||
#, unused
|
||||
msgid "workspace.viewport.click-to-close-path"
|
||||
msgstr "Pulsar para cerrar la ruta"
|
||||
|
||||
msgid "workspace.notification-pill.detail"
|
||||
msgstr "Detalles"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue