diff --git a/CHANGES.md b/CHANGES.md index c7a6f2993..9e8404623 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,6 +17,7 @@ - Fix position problems cutting-pasting a component [Taiga #10677](https://tree.taiga.io/project/penpot/issue/10677) - Fix design tab has a horizontal scroll [Taiga #10660](https://tree.taiga.io/project/penpot/issue/10660) - Fix long file names being clipped when longer than allowed length [Taiga #10662](https://tree.taiga.io/project/penpot/issue/10662) +- Fix problem with error detail in toast [Taiga #10519](https://tree.taiga.io/project/penpot/issue/10519) ## 2.6.1 diff --git a/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.cljs b/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.cljs index e69475d1f..f4bacee8e 100644 --- a/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.cljs +++ b/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.cljs @@ -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])])])) diff --git a/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.scss b/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.scss index 3b6e4d5ff..febab627b 100644 --- a/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.scss +++ b/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.scss @@ -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); +} diff --git a/frontend/src/app/main/ui/ds/notifications/toast.cljs b/frontend/src/app/main/ui/ds/notifications/toast.cljs index ee21818a1..e100cd0c7 100644 --- a/frontend/src/app/main/ui/ds/notifications/toast.cljs +++ b/frontend/src/app/main/ui/ds/notifications/toast.cljs @@ -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 diff --git a/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx b/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx index 99f8857fb..5c6ff2b3d 100644 --- a/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx +++ b/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx @@ -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: diff --git a/frontend/src/app/main/ui/notifications.cljs b/frontend/src/app/main/ui/notifications.cljs index e78ac7494..de7161db9 100644 --- a/frontend/src/app/main/ui/notifications.cljs +++ b/frontend/src/app/main/ui/notifications.cljs @@ -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])))) diff --git a/frontend/src/app/main/ui/workspace/tokens/errors.cljs b/frontend/src/app/main/ui/workspace/tokens/errors.cljs index 1d9213c4d..d5c9918f3 100644 --- a/frontend/src/app/main/ui/workspace/tokens/errors.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/errors.cljs @@ -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))))))) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 5cb6da341..7379d944a 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -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) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index b3cd2df00..8e585a453 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -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" + diff --git a/frontend/translations/es.po b/frontend/translations/es.po index f74563af4..2e39ff01a 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -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"