Improve workspace debug sidebar workflow (#10678)

This commit is contained in:
Pablo Alba 2026-07-14 12:42:19 +02:00 committed by GitHub
parent c11d3aaaa7
commit 95cfbf5f7c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 109 additions and 38 deletions

View File

@ -1568,6 +1568,7 @@
(dm/export dwcp/paste-shapes)
(dm/export dwcp/paste-data-valid?)
(dm/export dwcp/copy-link-to-clipboard)
(dm/export dwcp/copy-id-to-clipboard)
(dm/export dwcp/copy-as-image)
;; Drawing

View File

@ -1138,6 +1138,15 @@
(watch [_ _ _]
(clipboard/to-clipboard (rt/get-current-href)))))
(defn copy-id-to-clipboard
[id]
(ptk/reify ::copy-id-to-clipboard
ptk/WatchEvent
(watch [_ _ _]
(->> (rx/from (clipboard/to-clipboard id))
(rx/map (fn [_]
(ntf/info "The id has been copied to the clipboard")))))))
(defn copy-as-image
[]
(ptk/reify ::copy-as-image

View File

@ -53,7 +53,7 @@
:add #{:tokens}}})
(def valid-options-mode
#{:design :prototype :inspect})
#{:design :prototype :inspect :debug})
(def default-layout
#{:sitemap

View File

@ -37,6 +37,7 @@
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.main.ui.workspace.sidebar.assets.common :as cmm]
[app.util.clipboard :as clipboard]
[app.util.debug :as dbg]
[app.util.dom :as dom]
[app.util.i18n :refer [tr] :as i18n]
[app.util.shape-icon :as usi]
@ -152,6 +153,7 @@
do-copy #(st/emit! (dw/copy-selected))
do-copy-link #(st/emit! (dw/copy-link-to-clipboard))
do-copy-id #(st/emit! (dw/copy-id-to-clipboard (-> shapes first :id str)))
do-cut #(st/emit! (dw/copy-selected)
(dw/delete-selected))
@ -200,6 +202,10 @@
(reset! enabled-paste-props* false))))))]
[:*
(when (and (not multiple?)
(dbg/enabled? :show-ids))
[:> menu-entry* {:title (tr "workspace.shape.menu.copy-id")
:on-click do-copy-id}])
[:> menu-entry* {:title (tr "workspace.shape.menu.copy")
:shortcut (sc/get-tooltip :copy)
:on-click do-copy}]

View File

@ -33,7 +33,6 @@
[app.main.ui.workspace.right-header :refer [right-header*]]
[app.main.ui.workspace.sidebar.assets :refer [assets-toolbox*]]
[app.main.ui.workspace.sidebar.debug :refer [debug-panel*]]
[app.main.ui.workspace.sidebar.debug-shape-info :refer [debug-shape-info*]]
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
[app.main.ui.workspace.sidebar.layers :refer [layers-toolbox*]]
[app.main.ui.workspace.sidebar.options :refer [options-toolbox*]]
@ -41,7 +40,6 @@
[app.main.ui.workspace.sidebar.sitemap :refer [sitemap*]]
[app.main.ui.workspace.sidebar.versions :refer [versions-toolbox*]]
[app.main.ui.workspace.tokens.sidebar :refer [tokens-sidebar-tab*]]
[app.util.debug :as dbg]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[rumext.v2 :as mf]))
@ -285,18 +283,16 @@
(let [is-comments? (= drawing-tool :comments)
is-history? (contains? layout :document-history)
is-inspect? (= section :inspect)
dbg-shape-panel? (dbg/enabled? :shape-panel)
is-debug? (= section :debug)
current-section* (mf/use-state :info)
current-section (deref current-section*)
can-be-expanded?
(or dbg-shape-panel?
(and (not is-comments?)
(not is-history?)
is-inspect?
(= current-section :code)))
(and (not is-comments?)
(not is-history?)
is-inspect?
(= current-section :code))
{on-pointer-down :on-pointer-down
on-lost-pointer-capture :on-lost-pointer-capture
@ -325,15 +321,16 @@
[:aside
{:class (stl/css-case :right-settings-bar true
:not-expand (not can-be-expanded?)
:expanded (> width right-sidebar-default-width))
:expanded (or is-debug? (> width right-sidebar-default-width)))
:id "right-sidebar-aside"
:data-testid "right-sidebar"
:data-size (str width)
:on-context-menu dom/prevent-default-context-menu
:style {:--right-sidebar-width (if can-be-expanded?
(dm/str width "px")
(dm/str right-sidebar-default-width "px"))}}
:style {:--right-sidebar-width (cond
is-debug? (dm/str right-sidebar-default-max-width "px")
can-be-expanded? (dm/str width "px")
:else (dm/str right-sidebar-default-width "px"))}}
(when can-be-expanded?
[:div {:class (stl/css :resize-area)
@ -348,9 +345,6 @@
[:div {:class (stl/css :settings-bar-inside)}
(cond
dbg-shape-panel?
[:> debug-shape-info*]
is-comments?
[:> comments-sidebar* {}]

View File

@ -18,15 +18,28 @@
[app.util.i18n :refer [tr]]
[rumext.v2 :as mf]))
(def ^:private no-reload-options
"Debug options that don't require a page reload to take effect.
These options are handled reactively via okulary subscriptions."
#{:shape-panel
:show-ids
:show-touched})
(mf/defc debug-panel*
[{:keys [class]}]
(let [on-toggle-enabled
(let [;; dbg/state is an okulary atom; deref'ing it makes this component
;; re-render whenever any debug option is toggled, so checkboxes
;; reflect the current state without a page reload.
_dbg (mf/deref dbg/state)
on-toggle-enabled
(mf/use-fn
(fn [event option]
(dom/prevent-default event)
(dom/stop-propagation event)
(dbg/toggle! option)
(js* "app.main.reinit(true)")))
(when-not (contains? no-reload-options option)
(js* "app.main.reinit(true)"))))
handle-close
(mf/use-fn

View File

@ -13,7 +13,6 @@
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.ds.product.panel-title :refer [panel-title*]]
[debug :as dbg]
[rumext.v2 :as mf]))
@ -125,10 +124,6 @@
(map (d/getf objects)))]
[:div {:class (stl/css :shape-info)}
[:> panel-title* {:class (stl/css :shape-info-title)
:text "Debug"
:on-close #(dbg/disable! :shape-panel)}]
(if (empty? selected)
[:div {:class (stl/css :attrs-container)} "No shapes selected"]
(for [[idx current] (d/enumerate selected)]

View File

@ -26,7 +26,11 @@
type-comp type-frame component-id is-hidden is-blocked
variant-id variant-name variant-properties variant-error
on-tab-press ref]}]
(let [edition* (mf/use-state false)
(let [;; Subscribe to dbg/state so the component re-renders when
;; :show-ids or :show-touched are toggled without a page reload.
_dbg (mf/deref dbg/state)
edition* (mf/use-state false)
edition? (deref edition*)
local-ref (mf/use-ref)

View File

@ -21,6 +21,7 @@
[app.main.ui.context :as ctx]
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
[app.main.ui.inspect.right-sidebar :as hrs]
[app.main.ui.workspace.sidebar.debug-shape-info :refer [debug-shape-info*]]
[app.main.ui.workspace.sidebar.options.drawing :as drawing]
[app.main.ui.workspace.sidebar.options.menus.align :refer [align-options*]]
[app.main.ui.workspace.sidebar.options.menus.bool :refer [bool-options*]]
@ -38,6 +39,7 @@
[app.main.ui.workspace.sidebar.options.shapes.rect :as rect]
[app.main.ui.workspace.sidebar.options.shapes.svg-raw :as svg-raw]
[app.main.ui.workspace.sidebar.options.shapes.text :as text]
[app.util.debug :as dbg]
[app.util.i18n :as i18n :refer [tr]]
[okulary.core :as l]
[rumext.v2 :as mf]))
@ -199,13 +201,17 @@
[:> hrs/right-sidebar* props]))
(def ^:private options-tabs
[{:label (tr "workspace.options.design")
:id "design"}
{:label (tr "workspace.options.prototype")
:id "prototype"}
{:label (tr "workspace.options.inspect")
:id "inspect"}])
(defn- generate-options-tabs
[]
(cond-> [{:label (tr "workspace.options.design")
:id "design"}
{:label (tr "workspace.options.prototype")
:id "prototype"}
{:label (tr "workspace.options.inspect")
:id "inspect"}]
(dbg/enabled? :shape-panel)
(conj {:label "Debug"
:id "debug"})))
(defn- on-option-tab-change
[mode]
@ -225,9 +231,28 @@
options-mode
(mf/deref refs/options-mode-global)
;; dbg/state is an okulary atom; deref'ing it makes this component
;; re-render when debug options change (e.g. :shape-panel toggle)
;; so the tabs list is regenerated reactively without a page reload.
dbg-state
(mf/deref dbg/state)
shapes
(mf/with-memo [selected objects]
(sequence (keep (d/getf objects)) selected))]
(sequence (keep (d/getf objects)) selected))
options-tabs
(generate-options-tabs)]
(mf/use-effect
(mf/deps dbg-state)
(fn []
(if (contains? dbg-state :shape-panel)
;; shape-panel was just enabled: select the debug tab
(on-option-tab-change "debug")
;; shape-panel was just disabled: if debug tab is active, go back to design
(when (= options-mode :debug)
(on-option-tab-change "design")))))
[:div {:class (stl/css :tool-window)}
(if (and (:can-edit permissions) (not render-context-lost?))
@ -255,7 +280,10 @@
:objects objects
:page-id page-id
:file-id file-id
:shapes shapes}])]
:shapes shapes}]
:debug
[:> debug-shape-info*])]
[:div {:class (stl/css :element-options :inspect-options :read-only)}
[:> inspect-tab* {:page-id page-id

View File

@ -6,9 +6,11 @@
(ns app.util.debug
(:require
[app.main.store :as st]))
[app.main.store :as st]
[app.util.storage :as storage]
[okulary.core :as l]))
(defonce state (atom #{#_:events}))
(def ^:private storage-key :app.util.debug/enabled-options)
(def options
#{;; Displays the bounding box for the shapes
@ -105,6 +107,17 @@
;; Event times
:events-times})
(defn- load-state
[]
(let [stored (get storage/user storage-key #{})]
(into #{} (filter options) stored)))
(defonce state (l/atom (load-state)))
(defn- persist-state!
[state]
(swap! storage/user assoc storage-key state))
(defn handle-change
[]
(set! st/*debug-events* (contains? @state :events))
@ -112,7 +125,9 @@
(when *assert*
(handle-change)
(add-watch state :watcher handle-change))
(add-watch state :watcher handle-change)
(add-watch state :persistence (fn [_ _ _ new-state]
(persist-state! new-state))))
(defn enable!
[option]

View File

@ -8779,6 +8779,9 @@ msgstr "Copy as CSS (nested layers)"
msgid "workspace.shape.menu.copy-link"
msgstr "Copy link"
msgid "workspace.shape.menu.copy-id"
msgstr "Copy id"
#: src/app/main/ui/workspace/context_menu.cljs:219
msgid "workspace.shape.menu.copy-paste-as"
msgstr "Copy/Paste as ..."

View File

@ -4629,7 +4629,7 @@ msgid "onboarding.choice.team-up.invite-members"
msgstr "Invitar integrantes"
msgid "onboarding.choice.team-up.invite-members-desc"
msgstr ""
msgstr ""
"Personas de desarrollo, diseño, gestión... todo el mundo es bienvenido. "
"Podrás invitar a más gente posteriormente."
@ -8551,6 +8551,9 @@ msgstr "Copiar como CSS (capas anidadas)"
msgid "workspace.shape.menu.copy-link"
msgstr "Copiar enlace"
msgid "workspace.shape.menu.copy-id"
msgstr "Copiar id"
#: src/app/main/ui/workspace/context_menu.cljs:219
msgid "workspace.shape.menu.copy-paste-as"
msgstr "Copiar/Pegar como ..."