mirror of
https://github.com/penpot/penpot.git
synced 2025-12-12 06:24:17 +01:00
🐛 Load dependant libraries, and don't allow unload them
This commit is contained in:
@@ -41,6 +41,7 @@
|
|||||||
- Fix long font names overlap [Taiga #11844](https://tree.taiga.io/project/penpot/issue/11844)
|
- 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 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 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
|
## 2.10.0
|
||||||
|
|
||||||
|
|||||||
@@ -608,8 +608,16 @@
|
|||||||
{:components components
|
{:components components
|
||||||
:variant-ids variant-ids}))
|
:variant-ids variant-ids}))
|
||||||
|
|
||||||
|
;;coalesce(string_agg(flr.library_file_id::text, ','), '') as library_file_ids
|
||||||
(def ^:private sql:team-shared-files
|
(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.revn,
|
||||||
f.vern,
|
f.vern,
|
||||||
f.data,
|
f.data,
|
||||||
@@ -622,10 +630,12 @@
|
|||||||
f.version,
|
f.version,
|
||||||
f.is_shared,
|
f.is_shared,
|
||||||
ft.media_id,
|
ft.media_id,
|
||||||
p.team_id
|
p.team_id,
|
||||||
|
fla.library_file_ids
|
||||||
from file as f
|
from file as f
|
||||||
inner join project as p on (p.id = f.project_id)
|
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_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
|
where f.is_shared = true
|
||||||
and f.deleted_at is null
|
and f.deleted_at is null
|
||||||
and p.deleted_at is null
|
and p.deleted_at is null
|
||||||
@@ -669,6 +679,8 @@
|
|||||||
(dissoc :media-id)
|
(dissoc :media-id)
|
||||||
(assoc :thumbnail-id media-id))
|
(assoc :thumbnail-id media-id))
|
||||||
(dissoc row :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 #(assoc % :library-summary (get-library-summary cfg %)))
|
||||||
(map #(dissoc % :data))))))
|
(map #(dissoc % :data))))))
|
||||||
|
|
||||||
@@ -1065,6 +1077,7 @@
|
|||||||
[:library-id ::sm/uuid]])
|
[:library-id ::sm/uuid]])
|
||||||
|
|
||||||
(sv/defmethod ::link-file-to-library
|
(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"
|
{::doc/added "1.17"
|
||||||
::webhooks/event? true
|
::webhooks/event? true
|
||||||
::sm/params schema:link-file-to-library}
|
::sm/params schema:link-file-to-library}
|
||||||
@@ -1078,7 +1091,8 @@
|
|||||||
(fn [{:keys [::db/conn]}]
|
(fn [{:keys [::db/conn]}]
|
||||||
(check-edition-permissions! conn profile-id file-id)
|
(check-edition-permissions! conn profile-id file-id)
|
||||||
(check-edition-permissions! conn profile-id library-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
|
;; --- MUTATION COMMAND: unlink-file-from-library
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,6 @@
|
|||||||
|
|
||||||
(declare ^:private workspace-initialized)
|
(declare ^:private workspace-initialized)
|
||||||
(declare ^:private fetch-libraries)
|
(declare ^:private fetch-libraries)
|
||||||
(declare ^:private libraries-fetched)
|
|
||||||
|
|
||||||
;; --- Initialize Workspace
|
;; --- Initialize Workspace
|
||||||
|
|
||||||
@@ -185,16 +184,6 @@
|
|||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update state :files assoc (:id library) library))))
|
(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
|
(defn- fetch-libraries
|
||||||
[file-id features]
|
[file-id features]
|
||||||
(ptk/reify ::fetch-libries
|
(ptk/reify ::fetch-libries
|
||||||
@@ -204,7 +193,7 @@
|
|||||||
(rx/mapcat
|
(rx/mapcat
|
||||||
(fn [libraries]
|
(fn [libraries]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (libraries-fetched file-id libraries))
|
(rx/of (dwl/libraries-fetched file-id libraries))
|
||||||
(rx/merge
|
(rx/merge
|
||||||
(->> (rx/from libraries)
|
(->> (rx/from libraries)
|
||||||
(rx/merge-map
|
(rx/merge-map
|
||||||
|
|||||||
@@ -1381,6 +1381,32 @@
|
|||||||
|
|
||||||
;; --- Link and unlink Files
|
;; --- 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
|
(defn link-file-to-library
|
||||||
[file-id library-id]
|
[file-id library-id]
|
||||||
(ptk/reify ::attach-library
|
(ptk/reify ::attach-library
|
||||||
@@ -1390,41 +1416,26 @@
|
|||||||
:file-id file-id
|
:file-id file-id
|
||||||
:library-id library-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
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [libraries (:shared-files state)
|
(let [libraries (:shared-files state)
|
||||||
library (get libraries library-id)
|
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/concat
|
||||||
(rx/merge
|
(rx/merge
|
||||||
(->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id})
|
(->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id})
|
||||||
(rx/ignore))
|
(rx/merge-map (fn [libraries-to-load]
|
||||||
(->> (rp/cmd! :get-file {:id library-id :features features})
|
(as-> libraries-to-load $
|
||||||
(rx/merge-map fpmap/resolve-file)
|
(remove loaded-libraries $)
|
||||||
;; FIXME: this should call the libraries-fetched event instead of ad-hoc assoc event
|
(conj $ library-id)
|
||||||
(rx/map (fn [file]
|
(map #(load-library-file file-id %) $))))))
|
||||||
(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/of (ptk/reify ::attach-library-finished))
|
(rx/of (ptk/reify ::attach-library-finished))
|
||||||
(when (pos? variants-count)
|
(when (pos? variants-count)
|
||||||
(->> (rp/cmd! :get-library-usage {:file-id library-id})
|
(->> (rp/cmd! :get-library-usage {:file-id library-id})
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
[app.main.ui.components.search-bar :refer [search-bar*]]
|
[app.main.ui.components.search-bar :refer [search-bar*]]
|
||||||
[app.main.ui.components.title-bar :refer [title-bar*]]
|
[app.main.ui.components.title-bar :refer [title-bar*]]
|
||||||
[app.main.ui.context :as ctx]
|
[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.foundations.assets.icon :as i]
|
||||||
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
||||||
[app.main.ui.hooks :as h]
|
[app.main.ui.hooks :as h]
|
||||||
@@ -48,9 +49,6 @@
|
|||||||
(def ^:private add-icon
|
(def ^:private add-icon
|
||||||
(deprecated-icon/icon-xref :add (stl/css :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
|
(def ^:private library-icon
|
||||||
(deprecated-icon/icon-xref :library (stl/css :library-icon)))
|
(deprecated-icon/icon-xref :library (stl/css :library-icon)))
|
||||||
|
|
||||||
@@ -199,7 +197,20 @@
|
|||||||
empty-library? (empty-library? summary)
|
empty-library? (empty-library? summary)
|
||||||
|
|
||||||
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
|
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
|
shared-libraries
|
||||||
(mf/with-memo [shared-libraries linked-libraries file-id search-term]
|
(mf/with-memo [shared-libraries linked-libraries file-id search-term]
|
||||||
@@ -208,18 +219,29 @@
|
|||||||
(remove #(= (:id %) file-id))
|
(remove #(= (:id %) file-id))
|
||||||
(remove #(contains? linked-libraries (:id %)))
|
(remove #(contains? linked-libraries (:id %)))
|
||||||
(filter #(matches-search (:name %) search-term))
|
(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)))))
|
(sort-by (comp str/lower :name)))))
|
||||||
|
|
||||||
linked-libraries
|
linked-libraries
|
||||||
(mf/with-memo [linked-libraries]
|
(mf/with-memo [linked-libraries find-connected-to library-names]
|
||||||
(->> (vals linked-libraries)
|
(->> (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))))
|
(sort-by (comp str/lower :name))))
|
||||||
|
|
||||||
|
linked-libraries-ids (mf/with-memo [linked-libraries]
|
||||||
|
(into #{} (map :id) linked-libraries))
|
||||||
|
|
||||||
|
|
||||||
importing* (mf/use-state nil)
|
importing* (mf/use-state nil)
|
||||||
sample-libraries [{:id "penpot-design-system", :name "Design system example"}
|
sample-libraries [{:id "penpot-design-system", :name "Design system example"}
|
||||||
{:id "wireframing-kit", :name "Wireframe library"}
|
{:id "wireframing-kit", :name "Wireframe library"}
|
||||||
{:id "whiteboarding-kit", :name "Whiteboarding Kit"}]
|
{:id "whiteboarding-kit", :name "Whiteboarding Kit"}]
|
||||||
|
|
||||||
|
|
||||||
change-search-term
|
change-search-term
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
@@ -311,22 +333,30 @@
|
|||||||
:value (tr "common.publish")
|
:value (tr "common.publish")
|
||||||
:on-click 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]
|
||||||
[:div {:class (stl/css :section-list-item)
|
(let [disabled? (some #(contains? linked-libraries-ids %) connected-to)]
|
||||||
:key (dm/str id)
|
[:div {:class (stl/css :section-list-item)
|
||||||
:data-testid "library-item"}
|
:key (dm/str id)
|
||||||
[:div {:class (stl/css :item-content)}
|
:data-testid "library-item"}
|
||||||
[:div {:class (stl/css :item-name)} name]
|
[:div {:class (stl/css :item-content)}
|
||||||
[:ul {:class (stl/css :item-contents)}
|
[:div {:class (stl/css :item-name)} name]
|
||||||
(let [summary (get-library-summary data)]
|
[:ul {:class (stl/css :item-contents)}
|
||||||
[:> library-description* {:summary summary}])]]
|
(let [summary (get-library-summary data)]
|
||||||
|
[:*
|
||||||
|
[:> 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)
|
[:> icon-button* {:type "button"
|
||||||
:type "button"
|
:aria-label (tr "workspace.libraries.unlink-library-btn")
|
||||||
:title (tr "workspace.libraries.unlink-library-btn")
|
:icon i/detach
|
||||||
:data-library-id (dm/str id)
|
:data-library-id (dm/str id)
|
||||||
:on-click unlink-library}
|
:variant "secondary"
|
||||||
detach-icon]])]]
|
:disabled disabled?
|
||||||
|
:on-click unlink-library}]]))]]
|
||||||
|
|
||||||
[:div {:class (stl/css :shared-section)}
|
[:div {:class (stl/css :shared-section)}
|
||||||
[:> title-bar* {:collapsable false
|
[:> title-bar* {:collapsable false
|
||||||
|
|||||||
@@ -319,6 +319,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.connected-to-wrapper {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connected-to-values {
|
||||||
|
color: var(--color-foreground-primary);
|
||||||
|
}
|
||||||
|
|
||||||
// Modal Component v2 update
|
// Modal Component v2 update
|
||||||
.modal-v2-info {
|
.modal-v2-info {
|
||||||
width: px2rem(664);
|
width: px2rem(664);
|
||||||
|
|||||||
@@ -5554,6 +5554,9 @@ msgstr "see all changes"
|
|||||||
msgid "workspace.libraries.updates"
|
msgid "workspace.libraries.updates"
|
||||||
msgstr "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
|
#: 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"
|
msgid "workspace.notification-pill.detail"
|
||||||
msgstr "Details"
|
msgstr "Details"
|
||||||
|
|||||||
@@ -5583,6 +5583,9 @@ msgstr "ver todos los cambios"
|
|||||||
msgid "workspace.libraries.updates"
|
msgid "workspace.libraries.updates"
|
||||||
msgstr "ACTUALIZACIONES"
|
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
|
#: 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"
|
msgid "workspace.notification-pill.detail"
|
||||||
msgstr "Detalles"
|
msgstr "Detalles"
|
||||||
|
|||||||
Reference in New Issue
Block a user