🐛 Load dependant libraries, and don't allow unload them

This commit is contained in:
Pablo Alba
2025-09-30 09:55:21 +02:00
committed by GitHub
parent dff1ca23d3
commit cd9ba482e3
8 changed files with 121 additions and 62 deletions

View File

@@ -41,6 +41,7 @@
- Fix long font names overlap [Taiga #11844](https://tree.taiga.io/project/penpot/issue/11844)
- Fix paste behavior according to the selected element [Taiga #11979](https://tree.taiga.io/project/penpot/issue/11979)
- Fix problem with export size [#7160](https://github.com/penpot/penpot/issues/7160)
- Fix multi level library dependencies [Taiga #12155](https://tree.taiga.io/project/penpot/issue/12155)
## 2.10.0

View File

@@ -608,8 +608,16 @@
{:components components
:variant-ids variant-ids}))
;;coalesce(string_agg(flr.library_file_id::text, ','), '') as library_file_ids
(def ^:private sql:team-shared-files
"select f.id,
"with file_library_agg as (
select flr.file_id,
coalesce(array_agg(flr.library_file_id) filter (where flr.library_file_id is not null), '{}') as library_file_ids
from file_library_rel flr
group by flr.file_id
)
select f.id,
f.revn,
f.vern,
f.data,
@@ -622,10 +630,12 @@
f.version,
f.is_shared,
ft.media_id,
p.team_id
p.team_id,
fla.library_file_ids
from file as f
inner join project as p on (p.id = f.project_id)
left join file_thumbnail as ft on (ft.file_id = f.id and ft.revn = f.revn and ft.deleted_at is null)
left join file_library_agg as fla on fla.file_id = f.id
where f.is_shared = true
and f.deleted_at is null
and p.deleted_at is null
@@ -669,6 +679,8 @@
(dissoc :media-id)
(assoc :thumbnail-id media-id))
(dissoc row :media-id))))
(map (fn [row]
(update row :library-file-ids db/decode-pgarray #{})))
(map #(assoc % :library-summary (get-library-summary cfg %)))
(map #(dissoc % :data))))))
@@ -1065,6 +1077,7 @@
[:library-id ::sm/uuid]])
(sv/defmethod ::link-file-to-library
"Link a file to a library. Returns the recursive list of libraries used by that library"
{::doc/added "1.17"
::webhooks/event? true
::sm/params schema:link-file-to-library}
@@ -1078,7 +1091,8 @@
(fn [{:keys [::db/conn]}]
(check-edition-permissions! conn profile-id file-id)
(check-edition-permissions! conn profile-id library-id)
(link-file-to-library conn params))))
(link-file-to-library conn params)
(bfc/get-libraries cfg [library-id]))))
;; --- MUTATION COMMAND: unlink-file-from-library

View File

@@ -90,7 +90,6 @@
(declare ^:private workspace-initialized)
(declare ^:private fetch-libraries)
(declare ^:private libraries-fetched)
;; --- Initialize Workspace
@@ -185,16 +184,6 @@
(update [_ state]
(update state :files assoc (:id library) library))))
(defn- libraries-fetched
[file-id libraries]
(ptk/reify ::libraries-fetched
ptk/UpdateEvent
(update [_ state]
(update state :files merge
(->> libraries
(map #(assoc % :library-of file-id))
(d/index-by :id))))))
(defn- fetch-libraries
[file-id features]
(ptk/reify ::fetch-libries
@@ -204,7 +193,7 @@
(rx/mapcat
(fn [libraries]
(rx/concat
(rx/of (libraries-fetched file-id libraries))
(rx/of (dwl/libraries-fetched file-id libraries))
(rx/merge
(->> (rx/from libraries)
(rx/merge-map

View File

@@ -1381,6 +1381,32 @@
;; --- Link and unlink Files
(defn libraries-fetched
[file-id libraries]
(ptk/reify ::libraries-fetched
ptk/UpdateEvent
(update [_ state]
(update state :files merge
(->> libraries
(map #(assoc % :library-of file-id))
(d/index-by :id))))))
(defn- load-library-file
[file-id library-id]
(ptk/reify ::load-library-file
ptk/WatchEvent
(watch [_ state _]
(let [features (get state :features)]
(rx/merge
(->> (rp/cmd! :get-file {:id library-id :features features})
(rx/merge-map fpmap/resolve-file)
(rx/map (fn [file]
(libraries-fetched file-id [file]))))
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"})
(rx/map (fn [thumbnails]
(fn [state]
(update state :thumbnails merge thumbnails))))))))))
(defn link-file-to-library
[file-id library-id]
(ptk/reify ::attach-library
@@ -1390,41 +1416,26 @@
:file-id file-id
:library-id library-id})
;; NOTE: this event implements UpdateEvent protocol for perform an
;; optimistic update state for make the UI feel more responsive.
ptk/UpdateEvent
(update [_ state]
(let [libraries (:workspace-shared-files state)
library (d/seek #(= (:id %) library-id) libraries)]
(if library
(update state :files assoc library-id
(-> library
(dissoc :library-summary)
(assoc :library-of file-id)))
state)))
ptk/WatchEvent
(watch [_ state _]
(let [libraries (:shared-files state)
library (get libraries library-id)
features (get state :features)
variants-count (-> library :library-summary :components :variants-count)]
variants-count (-> library :library-summary :components :variants-count)
loaded-libraries (->> (dsh/lookup-libraries state)
(remove (fn [[_ lib]]
(or (nil? (:data lib))
(empty? (:data lib)))))
(map first)
set)]
(rx/concat
(rx/merge
(->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id})
(rx/ignore))
(->> (rp/cmd! :get-file {:id library-id :features features})
(rx/merge-map fpmap/resolve-file)
;; FIXME: this should call the libraries-fetched event instead of ad-hoc assoc event
(rx/map (fn [file]
(assoc file :library-of file-id)))
(rx/map (fn [file]
(fn [state]
(assoc-in state [:files library-id] file)))))
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"})
(rx/map (fn [thumbnails]
(fn [state]
(update state :thumbnails merge thumbnails))))))
(rx/merge-map (fn [libraries-to-load]
(as-> libraries-to-load $
(remove loaded-libraries $)
(conj $ library-id)
(map #(load-library-file file-id %) $))))))
(rx/of (ptk/reify ::attach-library-finished))
(when (pos? variants-count)
(->> (rp/cmd! :get-library-usage {:file-id library-id})

View File

@@ -30,6 +30,7 @@
[app.main.ui.components.search-bar :refer [search-bar*]]
[app.main.ui.components.title-bar :refer [title-bar*]]
[app.main.ui.context :as ctx]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
[app.main.ui.hooks :as h]
@@ -48,9 +49,6 @@
(def ^:private add-icon
(deprecated-icon/icon-xref :add (stl/css :add-icon)))
(def ^:private detach-icon
(deprecated-icon/icon-xref :detach (stl/css :detach-icon)))
(def ^:private library-icon
(deprecated-icon/icon-xref :library (stl/css :library-icon)))
@@ -199,7 +197,20 @@
empty-library? (empty-library? summary)
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
dependencies (mf/with-memo [shared-libraries]
(into {} (map (juxt :id :library-file-ids) (vals shared-libraries))))
library-names (mf/with-memo [shared-libraries]
(into {} (map (fn [{:keys [id name]}]
[id name])
(vals shared-libraries))))
find-connected-to
(mf/use-fn
(mf/deps dependencies)
(fn [library-id]
(->> dependencies
(keep (fn [[k v]] (when (contains? v library-id) k))))))
shared-libraries
(mf/with-memo [shared-libraries linked-libraries file-id search-term]
@@ -208,18 +219,29 @@
(remove #(= (:id %) file-id))
(remove #(contains? linked-libraries (:id %)))
(filter #(matches-search (:name %) search-term))
(map #(assoc % :connected-to (find-connected-to (:id %))))
(map #(assoc % :connected-to-names (->> (:connected-to %)
(keep library-names))))
(sort-by (comp str/lower :name)))))
linked-libraries
(mf/with-memo [linked-libraries]
(mf/with-memo [linked-libraries find-connected-to library-names]
(->> (vals linked-libraries)
(map #(assoc % :connected-to (find-connected-to (:id %))))
(map #(assoc % :connected-to-names (->> (:connected-to %)
(keep library-names))))
(sort-by (comp str/lower :name))))
linked-libraries-ids (mf/with-memo [linked-libraries]
(into #{} (map :id) linked-libraries))
importing* (mf/use-state nil)
sample-libraries [{:id "penpot-design-system", :name "Design system example"}
{:id "wireframing-kit", :name "Wireframe library"}
{:id "whiteboarding-kit", :name "Whiteboarding Kit"}]
change-search-term
(mf/use-fn
(fn [event]
@@ -311,7 +333,8 @@
:value (tr "common.publish")
:on-click publish}])]
(for [{:keys [id name data] :as library} linked-libraries]
(for [{:keys [id name data connected-to connected-to-names] :as library} linked-libraries]
(let [disabled? (some #(contains? linked-libraries-ids %) connected-to)]
[:div {:class (stl/css :section-list-item)
:key (dm/str id)
:data-testid "library-item"}
@@ -319,14 +342,21 @@
[:div {:class (stl/css :item-name)} name]
[:ul {:class (stl/css :item-contents)}
(let [summary (get-library-summary data)]
[:> library-description* {:summary summary}])]]
[:*
[:> library-description* {:summary summary}]
(when (seq connected-to)
[:div {:class (stl/css :connected-to-wrapper)}
[:span "(" (tr "workspace.libraries.connected-to") " "]
[:span {:class (stl/css :connected-to-values)} (str/join ", " connected-to-names)]
[:span ")"]])])]]
[:button {:class (stl/css :item-button)
:type "button"
:title (tr "workspace.libraries.unlink-library-btn")
[:> icon-button* {:type "button"
:aria-label (tr "workspace.libraries.unlink-library-btn")
:icon i/detach
:data-library-id (dm/str id)
:on-click unlink-library}
detach-icon]])]]
:variant "secondary"
:disabled disabled?
:on-click unlink-library}]]))]]
[:div {:class (stl/css :shared-section)}
[:> title-bar* {:collapsable false

View File

@@ -319,6 +319,14 @@
}
}
.connected-to-wrapper {
display: block;
}
.connected-to-values {
color: var(--color-foreground-primary);
}
// Modal Component v2 update
.modal-v2-info {
width: px2rem(664);

View File

@@ -5554,6 +5554,9 @@ msgstr "see all changes"
msgid "workspace.libraries.updates"
msgstr "UPDATES"
msgid "workspace.libraries.connected-to"
msgstr "Connected to"
#: src/app/main/ui/ds/notifications/shared/notification_pill.cljs:67, src/app/main/ui/ds/notifications/shared/notification_pill.cljs:72
msgid "workspace.notification-pill.detail"
msgstr "Details"

View File

@@ -5583,6 +5583,9 @@ msgstr "ver todos los cambios"
msgid "workspace.libraries.updates"
msgstr "ACTUALIZACIONES"
msgid "workspace.libraries.connected-to"
msgstr "Conectada con"
#: src/app/main/ui/ds/notifications/shared/notification_pill.cljs:67, src/app/main/ui/ds/notifications/shared/notification_pill.cljs:72
msgid "workspace.notification-pill.detail"
msgstr "Detalles"