✨ Show an indicator on component copies with a missing main

A copy whose main component cannot be found looked like any other
copy, so users kept expecting updates that never came. The component
pill in the Design tab now shows a broken link icon, with a tooltip,
when the main component was deleted or its file is not connected.

A selection that mixes broken and healthy copies shows no indicator
for now, until design decides how it should look.

Relates to #12134

AI-assisted-by: claude-opus-5-5
This commit is contained in:
Eva Marco 2026-10-26 13:13:28 +01:00
parent 376ecda94e
commit d530d095bd
4 changed files with 45 additions and 3 deletions

View File

@ -40,6 +40,7 @@
[app.main.ui.ds.controls.switch :refer [switch*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.main.ui.ds.product.input-with-meta :refer [input-with-meta*]]
[app.main.ui.ds.tooltip.tooltip :refer [tooltip*]]
[app.main.ui.hooks :as h]
[app.main.ui.workspace.sidebar.assets.common :as cmm]
[app.main.ui.workspace.sidebar.options.menus.variants-help-modal]
@ -859,7 +860,7 @@
:on-enter-group on-enter-group}]))]]]]))
(mf/defc component-pill*
[{:keys [icon text subtext menu-entries disabled on-click]}]
[{:keys [icon text subtext menu-entries disabled on-click is-broken]}]
(let [menu-open* (mf/use-state false)
menu-open? (deref menu-open*)
@ -886,7 +887,8 @@
[:div {:class (stl/css :pill)}
[:button {:class (stl/css-case :pill-btn true
:with-menu menu-entries?)
:with-menu menu-entries?
:broken is-broken)
:data-testid "component-pill-button"
:on-click on-click
:disabled disabled}
@ -900,7 +902,13 @@
text]
(when subtext
[:div {:class (stl/css :pill-btn-subtext)}
subtext])]]
subtext])]
(when ^boolean is-broken
[:> tooltip* {:content (tr "workspace.options.component.broken")
:class (stl/css :pill-btn-broken)}
[:> icon* {:icon-id i/broken-link
:size "s"}]])]
(when menu-entries?
[:div {:class (stl/css :pill-actions)}
@ -924,6 +932,15 @@
:on-click (partial do-action action)}
[:span {:class (stl/css :pill-actions-dropdown-item-label)} title]]))]]])]))
(defn- broken-copy?
"True when the shape is a component copy whose main component cannot
be found: its library is not connected to the file, or the component
was deleted."
[shape component]
(and (not (ctk/main-instance? shape))
(or (nil? component)
(true? (:deleted component)))))
(mf/defc component-menu*
[{:keys [shapes is-swap-opened]}]
(let [current-file-id (mf/use-ctx ctx/current-file-id)
@ -951,6 +968,10 @@
{:include-deleted? true}) shapes)
same-variant? (ctv/same-variant? components)
;; TODO: a selection that mixes broken and healthy copies shows
;; no indicator until design decides how it should look (#12134).
all-broken? (every? true? (map broken-copy? shapes components))
;; For when it's only one shape
shape (first shapes)
id (:id shape)
@ -1076,6 +1097,7 @@
(cpn/merge-path-item-with-dot path (:name component))))
:on-click open-component-panel
:disabled (or is-swap-opened (not can-swap?))
:is-broken all-broken?
:menu-entries menu-entries}]
(when (and is-variant? main-instance?)
[:> icon-button* {:variant "ghost"

View File

@ -534,6 +534,10 @@
border-radius: $br-8 0 0 $br-8;
}
&.broken {
grid-template-columns: var(--sp-l) 1fr auto;
}
&:focus {
outline: $b-1 solid var(--color-accent-primary);
}
@ -544,6 +548,14 @@
}
}
// Marks a copy whose main component cannot be found.
.pill-btn-broken {
display: flex;
block-size: $sz-32;
align-items: center;
color: var(--color-accent-primary-muted);
}
.pill-btn-icon {
display: flex;
block-size: $sz-32;

View File

@ -7127,6 +7127,10 @@ msgstr "Component"
msgid "workspace.options.component.annotation"
msgstr "Annotation"
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:908
msgid "workspace.options.component.broken"
msgstr "Main component not found. This copy won’t receive updates."
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:1036
msgid "workspace.options.component.copy"
msgstr "Copy"

View File

@ -7212,6 +7212,10 @@ msgstr "Componente"
msgid "workspace.options.component.annotation"
msgstr "Nota"
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:908
msgid "workspace.options.component.broken"
msgstr "No se encuentra el componente principal. Esta copia no recibirá actualizaciones."
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:1036
msgid "workspace.options.component.copy"
msgstr "Copia"