🔥 Remove the components v1 leftovers

No components v1 file reaches the code any more: opening one fails the
feature check, and imports reject it or give it the feature. What only
served v1 goes:

- validate-file and validate-file-affected no longer skip a file
  without components/v2;
- the root of a deleted component is found by its main instance id
  only, in the type helper and the component sprite;
- generate-sync-library, which synced shapes inside live components,
  and the live components in containers-seq, so asset usages walk the
  pages only (deleted components keep their objects and still sync);
- the unused :components-v2 file option, from the schema, the file
  data and the test fixtures; stored files that carry it still
  validate;
- the team migration-in-progress check and its frontend alert, which
  leaves ephimeral features out of the team comparison;
- the components v2 introduction dialog, its styles and icons, and the
  :v2-info-shown profile prop;
- the graphic asset events and builders and the reads of graphics in
  the selection (the :add-media, :mod-media and :del-media changes stay,
  so stored changes still apply), and the uncalled render-page and
  render-components helpers.

AI-assisted-by: claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
alonso.torres 2026-10-11 23:06:25 +02:00
parent 31209d7c5d
commit d61ede802d
64 changed files with 151 additions and 636 deletions

View File

@ -398,7 +398,6 @@
(merge {:viewed-tutorial? false
:viewed-walkthrough? false
:nudge {:big 10 :small 1}
:v2-info-shown true
:release-notes-viewed (:main cf/version)}))
password (or (:password params) "!")

View File

@ -70,7 +70,6 @@
[:onboarding-questions {:optional true} [:map-of :keyword :string]]
[:onboarding-questions-answered {:optional true} ::sm/boolean]
[:nitrate-onboarding-viewed {:optional true} ::sm/boolean]
[:v2-info-shown {:optional true} ::sm/boolean]
[:release-notes-viewed {:optional true}
[::sm/text {:max 100}]]
[:notifications {:optional true} schema:props-notifications]

View File

@ -221,7 +221,6 @@
:id shape-id
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id shape-id
:name "image"
@ -343,7 +342,6 @@
:id shape-id
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id shape-id
:name "image"

View File

@ -95,7 +95,6 @@
:id shape-id
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id shape-id
:name "image"
@ -142,7 +141,6 @@
:id root-id
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id root-id
:name "svg-root"
@ -155,7 +153,6 @@
:id child-id
:parent-id root-id
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id child-id
:name "svg-text"
@ -186,8 +183,7 @@
file-id (first (:file-ids result))
imported (:result (th/command! {::th/type :get-file
::rpc/profile-id (:id profile)
:id file-id
:components-v2 true}))
:id file-id}))
root (get-in imported [:data :pages-index svg-raw-page-id
:objects svg-raw-root-id])]
@ -1654,8 +1650,7 @@
;; Get the imported file's data
(let [imported (:result (th/command! {::th/type :get-file
::rpc/profile-id (:id profile)
:id new-file-id
:components-v2 true}))
:id new-file-id}))
shapes (get-file-shapes (:data imported))]
;; Check that component-file references point to the new library
(doseq [shape shapes]
@ -1690,8 +1685,7 @@
;; Get the imported file's data
(let [imported (:result (th/command! {::th/type :get-file
::rpc/profile-id (:id profile)
:id new-file-id
:components-v2 true}))
:id new-file-id}))
file-data (:data imported)
pages (vals (:pages-index file-data))
all-shapes (mapcat vals (map :objects pages))
@ -1863,8 +1857,7 @@
original-lib-id (:id (first (:external-libraries manifest)))
imported (:result (th/command! {::th/type :get-file
::rpc/profile-id (:id profile)
:id new-file-id
:components-v2 true}))
:id new-file-id}))
file-data (:data imported)
pages (vals (:pages-index file-data))
all-shapes (mapcat vals (map :objects pages))
@ -1919,8 +1912,7 @@
original-lib-id (:id (first (:external-libraries manifest)))
imported (:result (th/command! {::th/type :get-file
::rpc/profile-id (:id viewer)
:id new-file-id
:components-v2 true}))
:id new-file-id}))
file-data (:data imported)
pages (vals (:pages-index file-data))
all-shapes (mapcat vals (map :objects pages))

View File

@ -94,8 +94,7 @@
(t/testing "query single file without users"
(let [data {::th/type :get-file
::rpc/profile-id (:id prof)
:id file-id
:components-v2 true}
:id file-id}
out (th/command! data)]
;; (th/print-result! out)
@ -120,8 +119,7 @@
(t/testing "query single file after delete"
(let [data {::th/type :get-file
::rpc/profile-id (:id prof)
:id file-id
:components-v2 true}
:id file-id}
out (th/command! data)]
(let [error (:error out)
error-data (ex-data error)]
@ -199,7 +197,6 @@
:id shape-id
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id shape-id
:name "image"
@ -292,7 +289,6 @@
:id shid
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id shid
:name "image"
@ -451,7 +447,6 @@
:id s1-shid
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id s1-shid
:name "image"
@ -465,7 +460,6 @@
:id s2-shid
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id s2-shid
:name "image"
@ -478,7 +472,6 @@
:id t-shid
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id t-shid
:name "text"
@ -1194,7 +1187,6 @@
:profile-id (:id prof)
:revn 0
:vern 0
:components-v2 true
:changes changes})
(t/testing "RPC page query (rendering purposes)"
@ -1679,7 +1671,6 @@
:id s-id-1
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id s-id-1
:name "Board"
@ -1696,7 +1687,6 @@
:id s-id-2
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id s-id-2
:name "Board"
@ -1840,7 +1830,6 @@
:id s-id-1
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id s-id-1
:name "Board"
@ -1871,7 +1860,6 @@
:id s-id-2
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id s-id-2
:name "Board"
@ -2040,7 +2028,6 @@
:id s-id-1
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id s-id-1
:name "Board"
@ -2072,7 +2059,6 @@
:id s-id-2
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id s-id-2
:name "Board"
@ -2174,7 +2160,6 @@
:id main-id
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id main-id
:name "Board"
@ -2204,7 +2189,6 @@
:id inst-id
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id inst-id
:name "Board"
@ -2494,7 +2478,6 @@
:id frame-id
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id frame-id
:name "frame"
@ -2506,7 +2489,6 @@
:id rect-id
:parent-id frame-id
:frame-id frame-id
:components-v2 true
:obj (cts/setup-shape
{:id rect-id
:name "rect"

View File

@ -50,7 +50,6 @@
:id shid
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id shid
:name "Artboard"

View File

@ -1526,8 +1526,7 @@
(t/testing "get-file after leaving fails with not-found"
(let [out (th/command! {::th/type :get-file
::rpc/profile-id (:id editor)
:id (:id file)
:components-v2 true})
:id (:id file)})
error (:error out)]
(t/is (th/ex-info? error))
(t/is (th/ex-of-type? error :not-found)))))))

View File

@ -74,8 +74,7 @@
(let [data {::th/type :get-view-only-bundle
::rpc/profile-id (:id prof)
:file-id (:id file)
:page-id (get-in file [:data :pages 0])
:components-v2 true}
:page-id (get-in file [:data :pages 0])}
out (th/command! data)]
@ -108,8 +107,7 @@
(let [data {::th/type :get-view-only-bundle
::rpc/profile-id (:id prof2)
:file-id (:id file)
:page-id (get-in file [:data :pages 0])
:components-v2 true}
:page-id (get-in file [:data :pages 0])}
out (th/command! data)]
;; (th/print-result! out)
@ -124,8 +122,7 @@
::rpc/profile-id (:id prof2)
:share-id @share-id
:file-id (:id file)
:page-id (get-in file [:data :pages 0])
:components-v2 true}
:page-id (get-in file [:data :pages 0])}
out (th/command! data)]
;; (th/print-result! out)
@ -139,8 +136,7 @@
(let [data {::th/type :get-view-only-bundle
:share-id @share-id
:file-id (:id file)
:page-id (get-in file [:data :pages 0])
:components-v2 true}
:page-id (get-in file [:data :pages 0])}
out (th/command! data)]
;; (th/print-result! out)
@ -390,8 +386,7 @@
(t/testing "control: non-member cannot read the library directly"
(let [out (th/command! {::th/type :get-file
::rpc/profile-id (:id stranger)
:id (:id lib)
:components-v2 true})
:id (:id lib)})
error-data (ex-data (:error out))]
(t/is (th/ex-info? (:error out)))
(t/is (= :not-found (:type error-data)))))
@ -552,7 +547,6 @@
:id n-main
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (frame n-main uuid/zero uuid/zero
{:main-instance true
:component-root true
@ -575,7 +569,6 @@
:id u-main
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (frame u-main uuid/zero uuid/zero
{:main-instance true
:component-root true
@ -586,7 +579,6 @@
:id u-child
:parent-id u-main
:frame-id u-main
:components-v2 true
:obj (frame u-child u-main u-main
{:main-instance false
:component-root true
@ -609,7 +601,6 @@
:id x-main
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (frame x-main uuid/zero uuid/zero
{:main-instance true
:component-root true
@ -637,7 +628,6 @@
:id inst
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (frame inst uuid/zero uuid/zero
{:main-instance false
:component-root true
@ -687,7 +677,6 @@
:id main
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id main
:name "Board"
@ -733,7 +722,6 @@
:id inst
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id inst
:name "Board"
@ -786,7 +774,6 @@
:id b-main
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id b-main
:name "Leaf"
@ -826,7 +813,6 @@
:id a-main
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id a-main
:name "Wrapper"
@ -842,7 +828,6 @@
:id a-child
:parent-id a-main
:frame-id a-main
:components-v2 true
:obj (cts/setup-shape
{:id a-child
:name "Leaf"
@ -875,7 +860,6 @@
:id inst
:parent-id uuid/zero
:frame-id uuid/zero
:components-v2 true
:obj (cts/setup-shape
{:id inst
:name "Wrapper"

View File

@ -260,40 +260,32 @@
(defn check-teams-compatibility!
[{source-features :features} {destination-features :features}]
(when (contains? source-features "ephimeral/migration")
(ex/raise :type :restriction
:code :migration-in-progress
:hint "the source team is in migration process"))
(let [source-features (into #{} xf-remove-ephimeral source-features)
destination-features (into #{} xf-remove-ephimeral destination-features)]
(when (contains? destination-features "ephimeral/migration")
(ex/raise :type :restriction
:code :migration-in-progress
:hint "the destination team is in migration process"))
(let [not-supported (-> (or source-features #{})
(set/difference destination-features)
(set/difference no-migration-features)
(set/difference default-features)
(seq))]
(when not-supported
(ex/raise :type :restriction
:code :team-feature-mismatch
:feature (first not-supported)
:hint (str/ffmt "the destination team does not have support '%' features"
(str/join "," not-supported)))))
(let [not-supported (-> (or destination-features #{})
(set/difference source-features)
(set/difference no-migration-features)
(set/difference default-features)
(seq))]
(when not-supported
(ex/raise :type :restriction
:code :team-feature-mismatch
:feature (first not-supported)
:hint (str/ffmt "the source team does not have support '%' features"
(str/join "," not-supported))))))
(let [not-supported (-> source-features
(set/difference destination-features)
(set/difference no-migration-features)
(set/difference default-features)
(seq))]
(when not-supported
(ex/raise :type :restriction
:code :team-feature-mismatch
:feature (first not-supported)
:hint (str/ffmt "the destination team does not have support '%' features"
(str/join "," not-supported)))))
(let [not-supported (-> destination-features
(set/difference source-features)
(set/difference no-migration-features)
(set/difference default-features)
(seq))]
(when not-supported
(ex/raise :type :restriction
:code :team-feature-mismatch
:feature (first not-supported)
:hint (str/ffmt "the source team does not have support '%' features"
(str/join "," not-supported)))))))
(defn check-paste-features!
"Function used for check feature compability between currently enabled

View File

@ -812,33 +812,6 @@
(update :undo-changes conj {:type :add-color :color prev-color})
(apply-changes-local))))
(defn add-media
[changes object]
(-> changes
(update :redo-changes conj {:type :add-media :object object})
(update :undo-changes conj {:type :del-media :id (:id object)})
(apply-changes-local)))
(defn update-media
[changes object]
(assert-library! changes)
(let [library-data (::library-data (meta changes))
prev-object (get-in library-data [:media (:id object)])]
(-> changes
(update :redo-changes conj {:type :mod-media :object object})
(update :undo-changes conj {:type :mod-media :object prev-object})
(apply-changes-local))))
(defn delete-media
[changes id]
(assert-library! changes)
(let [library-data (::library-data (meta changes))
prev-object (get-in library-data [:media id])]
(-> changes
(update :redo-changes conj {:type :del-media :id id})
(update :undo-changes conj {:type :add-media :object prev-object})
(apply-changes-local))))
(defn add-typography
[changes typography]
(-> changes

View File

@ -836,38 +836,37 @@
"Validate full referential integrity and semantic coherence on file data.
Return a list of errors or `nil`"
[{:keys [data features] :as file} libraries]
(when (contains? features "components/v2")
(binding [*errors* (volatile! [])]
[{:keys [data] :as file} libraries]
(binding [*errors* (volatile! [])]
;; `reduce-kv` is used throughout this function (and `validate-file-affected`)
;; instead of `(run! f (vals m))` or `(doseq [[k v] m])` because persistent
;; maps implement `IKVReduce`, which drives iteration internally without
;; first materialising an intermediate sequence of key-value pairs.
(reduce-kv
(fn [_ _ page]
(when (some? page)
;; Both performance caches are scoped to a single page: ref-shape
;; lookups and parent→children sets are page-local and must never
;; carry over to the next page. A fresh volatile is created for
;; each page so stale entries cannot corrupt subsequent pages.
(binding [*ref-shape-cache* (volatile! {})
*children-sets* (build-children-sets (:objects page))]
(check-shape uuid/zero file page libraries)
(run! #(check-shape % file page libraries)
(get-orphan-shapes page)))))
nil
(:pages-index data))
;; `reduce-kv` is used throughout this function (and `validate-file-affected`)
;; instead of `(run! f (vals m))` or `(doseq [[k v] m])` because persistent
;; maps implement `IKVReduce`, which drives iteration internally without
;; first materialising an intermediate sequence of key-value pairs.
(reduce-kv
(fn [_ _ page]
(when (some? page)
;; Both performance caches are scoped to a single page: ref-shape
;; lookups and parent→children sets are page-local and must never
;; carry over to the next page. A fresh volatile is created for
;; each page so stale entries cannot corrupt subsequent pages.
(binding [*ref-shape-cache* (volatile! {})
*children-sets* (build-children-sets (:objects page))]
(check-shape uuid/zero file page libraries)
(run! #(check-shape % file page libraries)
(get-orphan-shapes page)))))
nil
(:pages-index data))
(reduce-kv
(fn [_ _ component]
(check-component component file))
nil
(:components data))
(reduce-kv
(fn [_ _ component]
(check-component component file))
nil
(:components data))
(check-tokens file)
(check-tokens file)
(-> *errors* deref not-empty))))
(-> *errors* deref not-empty)))
(defn validate-shape
"Validate a shape and all its children. Returns a list of errors."
@ -946,34 +945,33 @@
to call on every incremental file update.
Returns a list of errors or `nil`."
[{:keys [data features] :as file} libraries changes]
(when (contains? features "components/v2")
(let [{:keys [page-ids component-ids]} (extract-affected-ids changes)]
(binding [*errors* (volatile! [])]
[{:keys [data] :as file} libraries changes]
(let [{:keys [page-ids component-ids]} (extract-affected-ids changes)]
(binding [*errors* (volatile! [])]
(reduce-kv
(fn [_ page-id page]
(when (and (some? page) (contains? page-ids page-id))
;; Both performance caches are scoped to a single page: ref-shape
;; lookups and parent→children sets are page-local and must never
;; carry over to the next page. A fresh volatile is created for
;; each page so stale entries cannot corrupt subsequent pages.
(binding [*ref-shape-cache* (volatile! {})
*children-sets* (build-children-sets (:objects page))]
(check-shape uuid/zero file page libraries)
(run! #(check-shape % file page libraries)
(get-orphan-shapes page)))))
nil
(:pages-index data))
(reduce-kv
(fn [_ page-id page]
(when (and (some? page) (contains? page-ids page-id))
;; Both performance caches are scoped to a single page: ref-shape
;; lookups and parent→children sets are page-local and must never
;; carry over to the next page. A fresh volatile is created for
;; each page so stale entries cannot corrupt subsequent pages.
(binding [*ref-shape-cache* (volatile! {})
*children-sets* (build-children-sets (:objects page))]
(check-shape uuid/zero file page libraries)
(run! #(check-shape % file page libraries)
(get-orphan-shapes page)))))
nil
(:pages-index data))
(reduce-kv
(fn [_ id component]
(when (contains? component-ids id)
(check-component component file)))
nil
(:components data))
(reduce-kv
(fn [_ id component]
(when (contains? component-ids id)
(check-component component file)))
nil
(:components data))
(-> *errors* deref not-empty)))))
(-> *errors* deref not-empty))))
(defn validate-file-affected!
"Like `validate-file-affected` but raises on the first non-empty

View File

@ -526,48 +526,6 @@
libraries
current-file-id)))))))))
(defn generate-sync-library
"Generate changes to synchronize all shapes in all components of the
local library of the given file, that use assets of the given type in
the given library.
If an asset id is given, only shapes linked to this particular asset will
be synchronized.
If early-return? is true, stops as soon as the first change is generated."
([changes file-id asset-type asset-id library-id libraries current-file-id]
(generate-sync-library changes file-id asset-type asset-id library-id libraries current-file-id false))
([changes file-id asset-type asset-id library-id libraries current-file-id early-return?]
(assert (contains? #{:colors :components :typographies} asset-type))
(assert (or (nil? asset-id) (uuid? asset-id)))
(assert (uuid? file-id))
(assert (uuid? library-id))
(container-log :info asset-id
:msg "Sync local components with library"
:asset-type asset-type
:asset-id asset-id
:file (pretty-file file-id libraries current-file-id)
:library (pretty-file library-id libraries current-file-id))
(let [file (get-in libraries [file-id :data])]
(loop [local-components (ctkl/components-seq file)
changes changes]
(let [local-component (first local-components)]
(if (or (nil? local-component)
(and early-return? (seq (:redo-changes changes))))
changes
(recur (next local-components)
(pcb/concat-changes ;;TODO Remove concat changes
changes
(generate-sync-container (pcb/empty-changes nil)
asset-type
asset-id
library-id
(cfh/make-container local-component :component)
libraries
current-file-id)))))))))
(defn- generate-sync-container
"Generate changes to synchronize all shapes in a particular container (a page
or a component) that use assets of the given type in the given library."
@ -587,9 +545,8 @@
(recur (next shapes)
(let [objects' (pcb/get-objects changes)
shape' (get objects' (:id shape))]
;; The shape could have been deleted in previous changes, if this nested component
;; comes from components-v1 era or if there has been some error with the swap slot.
;; In that case, we just skip it.
;; An earlier change of this loop may have deleted the shape (a broken
;; swap slot can do it); then it is skipped.
(if shape'
(generate-sync-shape asset-type
changes
@ -2772,11 +2729,6 @@
sync-typographies? (or (nil? asset-type) (= asset-type :typographies))
done? (fn [c] (and early-return? (seq (:redo-changes c))))]
(-> (pcb/set-undo-group changes undo-group)
;; library-changes
(maybe-sync sync-components? done? #(generate-sync-library % file-id :components asset-id library-id libraries current-file-id early-return?))
(maybe-sync sync-colors? done? #(generate-sync-library % file-id :colors asset-id library-id libraries current-file-id early-return?))
(maybe-sync sync-typographies? done? #(generate-sync-library % file-id :typographies asset-id library-id libraries current-file-id early-return?))
;; file-changes
(maybe-sync sync-components? done? #(generate-sync-file % file-id :components asset-id library-id libraries current-file-id early-return?))
(maybe-sync sync-colors? done? #(generate-sync-file % file-id :colors asset-id library-id libraries current-file-id early-return?))
(maybe-sync sync-typographies? done? #(generate-sync-file % file-id :typographies asset-id library-id libraries current-file-id early-return?))))))

View File

@ -1881,7 +1881,7 @@
page
(:objects page)
#{shape-id}
{:components-v2 true})
{})
file' (thf/apply-changes the-file changes)]
(-> situation
(tm/with-file file')

View File

@ -318,9 +318,7 @@
(defn get-deleted-component-root
[component]
(if (some? (:main-instance-id component))
(get-in component [:objects (:main-instance-id component)])
(get-in component [:objects (:id component)])))
(get-in component [:objects (:main-instance-id component)]))
(defn uses-library-components?
"Check if the shape uses any component in the given library."

View File

@ -233,7 +233,7 @@
(contains? visited (:id shape))
nil
(nil? (:parent-id shape)) ; This occurs in the root of components v1
(nil? (:parent-id shape)) ; A shape without parent ends the walk
shape
(ctk/main-instance? shape)

View File

@ -75,7 +75,6 @@
(def schema:options
[:map {:title "FileOptions"}
[:components-v2 {:optional true} ::sm/boolean]
[:base-font-size {:optional true} :string]])
(def schema:data
@ -157,8 +156,7 @@
(ctpl/add-page page)
:always
(update :options merge {:components-v2 true
:base-font-size BASE-FONT-SIZE})))))
(update :options merge {:base-font-size BASE-FONT-SIZE})))))
;; FIXME: we can't handle the "default" migrations for avoid providing
;; them all the time the file is created because we can't import file
@ -221,10 +219,10 @@
(update file :data f)))
(defn containers-seq
"Generate a sequence of all pages and all components, wrapped as containers"
"Generate a sequence of all pages, wrapped as containers. Live
components hold no objects: their main instances are page shapes."
[file-data]
(concat (map #(ctn/make-container % :page) (ctpl/pages-seq file-data))
(map #(ctn/make-container % :component) (ctkl/components-seq file-data))))
(map #(ctn/make-container % :page) (ctpl/pages-seq file-data)))
(defn object-containers-seq
"Generate a sequence of all pages and all deleted components (all those components that have :objects), wrapped as containers"
@ -707,8 +705,7 @@
assets)))
(defn used-in?
"Checks if a specific asset is used in a given file (by any shape in its pages or in
the components of the local library)."
"Checks if a specific asset is used in a given file (by any shape in its pages)."
[file-data library-id asset asset-type]
(letfn [(used-in-shape? [shape]
(uses-asset? asset-type shape library-id asset))

View File

@ -0,0 +1,34 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS SUBSIDIARY SL
(ns common-tests.features-test
(:require
[app.common.features :as cfeat]
[clojure.test :as t]))
(defn- incompatibility
"The code of the error raised when moving files between two teams
with the given features, or nil when they are compatible."
[source-features destination-features]
(try
(cfeat/check-teams-compatibility! {:features source-features}
{:features destination-features})
nil
(catch #?(:clj Exception :cljs :default) cause
(:code (ex-data cause)))))
(t/deftest teams-with-the-same-features-are-compatible
(t/is (nil? (incompatibility cfeat/default-features cfeat/default-features))))
(t/deftest a-feature-only-one-team-has-makes-them-incompatible
(let [features (conj cfeat/default-features "test/unknown")]
(t/is (= :team-feature-mismatch (incompatibility features cfeat/default-features)))
(t/is (= :team-feature-mismatch (incompatibility cfeat/default-features features)))))
(t/deftest ephimeral-features-left-on-a-team-are-ignored
(let [features (conj cfeat/default-features "ephimeral/migration")]
(t/is (nil? (incompatibility features cfeat/default-features)))
(t/is (nil? (incompatibility cfeat/default-features features)))))

View File

@ -71,16 +71,20 @@
:main-instance-page (uuid/next)})))))
;; ----------------------------------------------------------------
;; 1. Feature gate
;; 1. Features
;; ----------------------------------------------------------------
(t/deftest validate-file-affected-no-feature
(t/testing "returns nil when file does not have the components/v2 feature"
(t/deftest validate-file-whatever-its-features
(t/testing "a file without features is validated like any other"
(let [file (-> (thf/sample-file :file1 :page-label :page1)
(assoc :features #{}))
(assoc :features #{})
(inject-broken-child :page1))
page-id (thi/id :page1)
changes [{:type :add-obj :page-id page-id :id (uuid/next)}]]
(t/is (nil? (cfv/validate-file-affected file {} changes))))))
(t/is (some #(= :child-not-found (:code %))
(cfv/validate-file-affected file {} changes)))
(t/is (some #(= :child-not-found (:code %))
(cfv/validate-file file {}))))))
;; ----------------------------------------------------------------
;; 2. Empty changes – nothing to validate

View File

@ -380,7 +380,7 @@
page
(:objects page)
#{(:id root)}
{:components-v2 true})
{})
file' (thf/apply-changes file changes)
@ -421,7 +421,7 @@
page
(:objects page)
#{(:id root)}
{:components-v2 true})
{})
file-deleted (thf/apply-changes file changes)
page-deleted (thf/current-page file-deleted)
@ -465,7 +465,7 @@
page2
(:objects page2)
#{(:id root)}
{:components-v2 true})
{})
file (-> (thf/apply-changes file changes)
(ctf/update-file-data #(ctpl/delete-page % (:id page2))))
changes (cll/generate-restore-component (pcb/empty-changes)

View File

@ -187,7 +187,7 @@
page
(:objects page)
#{(:id copy-child)}
{:components-v2 true})
{})
file-mdf (thf/apply-changes file changes)
page-mdf (thf/current-page file-mdf)

View File

@ -253,7 +253,7 @@
page
(:objects page)
#{(:id main-child)}
{:components-v2 true})
{})
updated-file (thf/apply-changes file changes1)

View File

@ -154,7 +154,7 @@
page
(:objects page)
#{(:id copy-child)}
{:components-v2 true})
{})
file' (thf/apply-changes file changes)

View File

@ -16,6 +16,7 @@
[common-tests.buffer-test]
[common-tests.colors-test]
[common-tests.data-test]
[common-tests.features-test]
[common-tests.files-builder-test]
[common-tests.files-changes-test]
[common-tests.files-migrations-0025-test]
@ -129,6 +130,7 @@
'common-tests.buffer-test
'common-tests.colors-test
'common-tests.data-test
'common-tests.features-test
'common-tests.files-builder-test
'common-tests.files-changes-test
'common-tests.files-migrations-0025-test

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="4494 307 310 290"><path d="m4643.25 309.15-18.86 15.75a9.32 9.32 0 0 0-1.2 13.1 9.26 9.26 0 0 0 13.07 1.2l3.67-3.05.2 82.04a103.8 103.8 0 0 0-14.46-19.07c-15.68-16.23-36.46-25.7-59.17-26.11a86.83 86.83 0 0 0-11.04.52l1.91-3.29a9.32 9.32 0 0 0-3.42-12.57 9.26 9.26 0 0 0-12.6 3.2l-12.59 21.63a9.32 9.32 0 0 0 2.1 11.86l18.93 15.67a9.26 9.26 0 0 0 9.16 1.54 9.32 9.32 0 0 0 2.66-15.9l-4.42-3.66c21.64-2.66 40.4 4.82 55.14 20.07 16.68 17.27 27.77 45.12 27.98 79.86-.05 9.54.04 19.06.07 28.6-10.61-16.53-24.8-30.38-40.13-40.85-15.92-10.87-33.13-18.28-49.55-21.38-8.2-1.55-16.3-2.04-23.93-1.2-2.3.26-4.6.66-6.85 1.2l1.09-2.8a9.27 9.27 0 0 0-17.27-6.77l-9.1 23.32a9.32 9.32 0 0 0 3.91 11.4l21.13 12.53a9.26 9.26 0 0 0 12.54-3.37 9.32 9.32 0 0 0-3.1-12.65l-5.56-3.3c6.54-1.62 14.64-1.77 23.72-.05 13.42 2.53 28.56 8.92 42.53 18.46 27.92 19.09 50.72 50.2 50.72 87.3v.03l.02 5.3a9.3 9.3 0 0 0 9.3 9.29 9.29 9.29 0 0 0 9.25-9.32v-2.77c.5-37.1 19.92-67.3 48.22-89.72 13.17-9.62 27.44-15.99 39.99-18.46 10.08-2 18.76-1.4 25.26 1.19l-4 2.43a9.32 9.32 0 0 0-3.14 12.79 9.26 9.26 0 0 0 12.74 3.14l21.37-13a9.32 9.32 0 0 0 3.78-11.43l-9.17-22.82a9.27 9.27 0 1 0-17.21 6.96l1.72 4.29a50.78 50.78 0 0 0-11.87-2.93c-7.38-.92-15.18-.45-23.06 1.11-15.78 3.1-32.2 10.63-47.34 21.68a142.37 142.37 0 0 0-37.45 40.54l-.07-24.5c.65-34.78 11.26-64.22 26.98-82.93 15.4-18.33 34.64-26.71 56.88-22.07l-4.52 2.74a9.32 9.32 0 0 0-3 12.7 9.26 9.26 0 0 0 12.6 3.22l21.37-12.99a9.32 9.32 0 0 0 3.79-11.43l-9.17-22.83a9.27 9.27 0 0 0-12.08-5.15 9.32 9.32 0 0 0-5.14 12.11l1.5 3.74a73.41 73.41 0 0 0-19.47-1.8c-22.03.99-42.11 12.09-56.95 29.76a115.7 115.7 0 0 0-12.97 19.25l-.2-83.78 3.47 3.03a9.26 9.26 0 0 0 12.97-1.03 9.32 9.32 0 0 0-.8-13.02l-18.87-16.42a9.26 9.26 0 0 0-12.01-.13Z" paint-order="fill markers"/></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="4870 326 249.25 261.8"><path fill="#000" d="M5050.75 326.04a8.57 8.57 0 0 0-7.77 3.58l-19.12 27.03a8.57 8.57 0 0 0 0 9.9l19.12 27.04a8.57 8.57 0 0 0 15.44-3.5 8.57 8.57 0 0 0-1.45-6.4l-8.43-11.92c13.34-.5 22.4 1.84 28.61 5.26 6.78 3.74 10.6 8.83 13.14 14.83 2.54 6 3.51 12.91 3.77 19.07.24 6.16-.26 11.02-.19 15.04a8.57 8.57 0 0 0 8.7 8.43 8.57 8.57 0 0 0 8.44-8.69c-.02-1.7.47-8.1.17-15.49-.3-7.37-1.4-16.26-5.1-25.03a46.95 46.95 0 0 0-20.64-23.17c-9.83-5.43-22.72-8.14-39.22-7.3l10.75-15.21a8.57 8.57 0 0 0-2.05-11.93 8.56 8.56 0 0 0-4.17-1.54Zm-158.97 1.7A21.92 21.92 0 0 0 4870 349.5v61.37a21.92 21.92 0 0 0 21.77 21.78h61.38a21.92 21.92 0 0 0 21.78-21.77v-61.37a21.92 21.92 0 0 0-21.77-21.79h-61.38Zm0 17.13h61.37a4.46 4.46 0 0 1 4.64 4.64v61.37a4.46 4.46 0 0 1-4.63 4.65h-61.38a4.45 4.45 0 0 1-4.63-4.65v-61.37a4.45 4.45 0 0 1 4.63-4.63Zm-5.1 134.52a8.57 8.57 0 0 0-8.43 8.7c.02 1.7-.47 8.1-.17 15.47.3 7.37 1.4 16.26 5.1 25.04a47 47 0 0 0 20.65 23.18c9.83 5.41 22.7 8.14 39.2 7.3l-10.74 15.2a8.57 8.57 0 0 0 8.44 13.4 8.57 8.57 0 0 0 5.56-3.51l19.1-27.04a8.57 8.57 0 0 0 0-9.9l-19.1-27.03a8.57 8.57 0 0 0-5.56-3.5 8.57 8.57 0 0 0-8.44 13.4l8.42 11.92c-13.34.5-22.4-1.82-28.6-5.24-6.78-3.74-10.6-8.83-13.14-14.83-2.54-6.02-3.51-12.92-3.77-19.08-.24-6.16.26-11.02.2-15.03a8.57 8.57 0 0 0-8.71-8.45Zm152.1 1.74a24.6 24.6 0 0 0-24.46 24.46v56.02a24.6 24.6 0 0 0 24.47 24.45h56a24.6 24.6 0 0 0 24.46-24.45v-56.02a24.6 24.6 0 0 0-24.45-24.46h-56.02Zm0 17.14h56.02a7.12 7.12 0 0 1 7.31 7.32v56.02a7.11 7.11 0 0 1-7.31 7.3h-56.02a7.12 7.12 0 0 1-5.23-2.07 7.12 7.12 0 0 1-2.09-5.23v-56.02a7.11 7.11 0 0 1 7.33-7.32Z" class="fills" color="#000" paint-order="fill markers"/></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="4563 696 212.14 362.63"><path d="M4669.07 696a41.22 41.22 0 0 0-29.24 12.07l-64.76 64.75a41.47 41.47 0 0 0 0 58.49l8.39 8.39-8.39 8.38a41.47 41.47 0 0 0 0 58.5l8.38 8.38-8.36 8.37a41.47 41.47 0 0 0 0 58.49l64.73 64.73a41.48 41.48 0 0 0 58.5.01l64.74-64.73a41.49 41.49 0 0 0 0-58.51l-8.37-8.38 8.37-8.37a41.47 41.47 0 0 0 0-58.5l-8.38-8.37 8.39-8.38a41.47 41.47 0 0 0 0-58.5l-64.75-64.75a41.25 41.25 0 0 0-29.25-12.07Zm0 18.28a22.85 22.85 0 0 1 16.2 6.83l64.76 64.75a22.68 22.68 0 0 1 0 32.42l-64.74 64.75a22.68 22.68 0 0 1-32.43.01l-64.76-64.75a22.68 22.68 0 0 1 0-32.43l64.75-64.75a22.86 22.86 0 0 1 16.22-6.83Zm0 52.73c-4.3 0-8.62 1.62-11.85 4.85l-18.35 18.36a16.89 16.89 0 0 0 0 23.7l18.35 18.35a16.89 16.89 0 0 0 23.7 0l18.36-18.35a16.89 16.89 0 0 0-.01-23.7l-18.35-18.35a16.7 16.7 0 0 0-11.85-4.86Zm0 15.19c.34 0 .68.16 1.01.5l18.36 18.35c.66.67.68 1.38.01 2.05l-18.35 18.35c-.67.67-1.4.67-2.06 0l-18.36-18.35c-.66-.66-.65-1.39.01-2.05l18.35-18.35c.34-.33.68-.5 1.03-.5Zm-72.58 70.53 43.33 43.33a41.47 41.47 0 0 0 58.5.01l43.33-43.33 8.37 8.37a22.68 22.68 0 0 1 0 32.42l-64.75 64.75a22.68 22.68 0 0 1-32.43 0l-64.73-64.73a22.68 22.68 0 0 1 0-32.44Zm145.17 75.24 8.37 8.37a22.7 22.7 0 0 1 0 32.45l-64.74 64.74a22.7 22.7 0 0 1-32.44-.01l-64.73-64.74a22.67 22.67 0 0 1 0-32.42l8.36-8.37 43.33 43.33a41.47 41.47 0 0 0 58.5 0Z" paint-order="fill markers"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="4870 696 216.34 319.12"><path d="M5052.72 696a5.69 5.69 0 0 0-5.8 4.77c-1.72 10.62-4.08 20.19-7.8 27-3.71 6.79-8.19 10.82-15.77 12.25-6.11 1.16-6.17 9.92-.07 11.15 7.97 1.64 12.63 5.72 16.33 12.39 3.7 6.68 5.93 16.05 7.27 26.7.89 6.88 10.98 6.47 11.32-.46.83-18.37 4.47-27.31 8.37-31.76 3.9-4.45 8.67-5.56 15.17-6.85 5.8-1.12 6.24-9.26.6-11.01-7.53-2.35-12.77-6.54-16.73-12.94-3.95-6.4-6.46-15.15-7.41-26.06a5.69 5.69 0 0 0-5.48-5.18Zm-151.65 71.03c-17.13.1-31 13.97-31.07 31.1v185.9a31.21 31.21 0 0 0 31.07 31.09h136.32a31.24 31.24 0 0 0 31.1-31.08V871.7c0-6.01-1.92-12.93-6.51-17.91-21.13-22.9-59.2-64.23-73.79-78.82-4-4.01-10.62-7.95-17.97-7.95Zm0 18.43h65.88v71.29c0 6.42 4.03 12.41 8.53 15.12 4.51 2.71 9.05 3.33 13.15 3.33h61.43v108.83a12.44 12.44 0 0 1-12.67 12.66h-136.32a12.42 12.42 0 0 1-12.65-12.66v-185.9a12.44 12.44 0 0 1 12.65-12.67Zm84.31 13.15a5423.07 5423.07 0 0 1 54.24 58.17h-50.99a8.99 8.99 0 0 1-3.25-.62Z" paint-order="fill markers"/></svg>

Before

Width:  |  Height:  |  Size: 1012 B

View File

@ -242,62 +242,6 @@
(pcb/add-color new-color))]
(rx/of (dch/commit-changes changes))))))
;; FIXME: this should be deleted
(defn add-media
[media]
(let [media (ctf/check-file-media media)]
(ptk/reify ::add-media
ev/Event
(-data [_] media)
ptk/WatchEvent
(watch [it _ _]
(let [obj (select-keys media [:id :name :width :height :mtype])
changes (-> (pcb/empty-changes it)
(pcb/add-media obj))]
(rx/of (dch/commit-changes changes)))))))
(defn rename-media
[id new-name]
(dm/assert!
"expected valid uuid for `id`"
(uuid? id))
(dm/assert!
"expected valid string for `new-name`"
(string? new-name))
(ptk/reify ::rename-media
ptk/WatchEvent
(watch [it state _]
(let [new-name (str/trim new-name)]
(if (str/empty? new-name)
(rx/empty)
(let [[path name] (cpn/split-group-name new-name)
data (dsh/lookup-file-data state)
object (get-in data [:media id])
new-object (assoc object :path path :name name)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/update-media new-object))]
(rx/of (dch/commit-changes changes))))))))
(defn delete-media
[{:keys [id]}]
(assert (uuid? id) "expected valid uuid for `id`")
(ptk/reify ::delete-media
ev/Event
(-data [_] {:id id})
ptk/WatchEvent
(watch [it state _]
(let [data (dsh/lookup-file-data state)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/delete-media id))]
(rx/of (dch/commit-changes changes))))))
(defn add-typography
([typography] (add-typography typography true))
([typography edit?]

View File

@ -810,11 +810,6 @@
(defmethod ptk/handle-error :restriction
[{:keys [code] :as error}]
(cond
(= :migration-in-progress code)
(let [message (tr "errors.migration-in-progress" (:feature error))
on-accept (constantly nil)]
(st/emit! (modal/show {:type :alert :message message :on-accept on-accept})))
(= :team-feature-mismatch code)
(let [message (tr "errors.team-feature-mismatch" (:feature error))
on-accept (constantly nil)]

View File

@ -49,12 +49,10 @@
[app.main.ui.shapes.text.fontfaces :as ff]
[app.render-wasm.api :as wasm.api]
[app.util.dom :as dom]
[app.util.http :as http]
[app.util.strings :as ust]
[app.util.thumbnails :as th]
[app.util.timers :as ts]
[beicon.v2.core :as rx]
[clojure.set :as set]
[cuerdas.core :as str]
[promesa.core :as p]
[rumext.v2 :as mf]))
@ -575,8 +573,7 @@
[{:keys [component] :as props}]
(let [name (:name component)
path (:path component)
root-id (or (:main-instance-id component)
(:id component))
root-id (:main-instance-id component)
orig-root (get (:objects component) root-id)
objects (adapt-objects-for-shape (:objects component)
root-id)
@ -646,80 +643,6 @@
;; RENDER FOR DOWNLOAD (wrongly called exportation)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- get-image-data [shape]
(cond
(= :image (:type shape))
[(:metadata shape)]
(some? (:fill-image shape))
[(:fill-image shape)]
:else
[]))
(defn- populate-images-cache
[objects]
(let [images (->> objects
(vals)
(mapcat get-image-data))]
(->> (rx/from images)
(rx/map #(cfg/resolve-file-media %))
(rx/merge-map http/fetch-data-uri))))
(defn populate-fonts-cache [objects]
(let [texts (->> objects
(vals)
(filterv #(= (:type %) :text))
(mapv :content))]
(->> (rx/from texts)
(rx/map fonts/get-content-fonts)
(rx/reduce set/union #{})
(rx/merge-map identity)
(rx/merge-map fonts/fetch-font-css)
(rx/merge-map fonts/extract-fontface-urls)
(rx/merge-map http/fetch-data-uri))))
(defn render-page
[data]
(rx/concat
(->> (rx/merge
(populate-images-cache (:objects data))
(populate-fonts-cache (:objects data)))
(rx/ignore))
(->> (rx/of data)
(rx/map
(fn [data]
(let [elem (mf/element page-svg #js {:data data :embed true :include-metadata true})]
(rds/renderToStaticMarkup elem)))))))
(defn render-components
[data deleted?]
(let [;; Join all components objects into a single map
components (if (not deleted?)
(ctkl/components-seq data)
(ctkl/deleted-components-seq data))
objects (->> components
(map (partial ctf/load-component-objects data))
(map :objects)
(reduce conj))]
(rx/concat
(->> (rx/merge
(populate-images-cache objects)
(populate-fonts-cache objects))
(rx/ignore))
(->> (rx/of data)
(rx/map
(fn [data]
(let [elem (mf/element components-svg
#js {:data data
:embed true
:include-metadata true
:deleted? deleted?})]
(rds/renderToStaticMarkup elem))))))))
(defn render-frame
([objects shape object-id]
(render-frame objects shape object-id nil))

View File

@ -273,10 +273,6 @@
(def ^:icon tree (icon-xref :tree))
(def ^:icon unlock (icon-xref :unlock))
(def ^:icon user (icon-xref :user))
(def ^:icon v2-icon-1 (icon-xref :v2-icon-1))
(def ^:icon v2-icon-2 (icon-xref :v2-icon-2))
(def ^:icon v2-icon-3 (icon-xref :v2-icon-3))
(def ^:icon v2-icon-4 (icon-xref :v2-icon-4))
(def ^:icon variant (icon-xref :variant))
(def ^:icon vertical-align-items-center (icon-xref :vertical-align-items-center))
(def ^:icon vertical-align-items-end (icon-xref :vertical-align-items-end))

View File

@ -21,7 +21,6 @@
[app.main.data.dashboard :as dd]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.profile :as du]
[app.main.data.team :as dtm]
[app.main.data.workspace.colors :as mdc]
[app.main.data.workspace.libraries :as dwl]
@ -41,7 +40,6 @@
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
[app.main.ui.ds.product.empty-state :refer [empty-state*]]
[app.main.ui.hooks :as h]
[app.main.ui.icons :as deprecated-icon]
[app.main.ui.workspace.tokens.import-from-library]
[app.util.color :as uc]
[app.util.dom :as dom]
@ -1206,59 +1204,3 @@
:is-legacy (not token-lib-sync?)
:libraries linked-libraries}])]]]))
(mf/defc v2-info-dialog
{::mf/register modal/components
::mf/register-as :v2-info}
[]
(let [handle-gotit-click
(mf/use-fn
(fn []
(modal/hide!)
(st/emit! (du/update-profile-props {:v2-info-shown true}))))]
[:div {:class (stl/css :modal-overlay)}
[:div {:class (stl/css :modal-dialog :modal-v2-info)}
[:div {:class (stl/css :modal-v2-title)}
"IMPORTANT INFORMATION ABOUT NEW COMPONENTS"]
[:div {:class (stl/css :modal-content)}
[:div {:class (stl/css :info-content)}
[:div {:class (stl/css :info-block)}
[:div {:class (stl/css :info-icon)} deprecated-icon/v2-icon-1]
[:div {:class (stl/css :info-block-title)}
"One physical source of truth"]
[:div {:class (stl/css :info-block-content)}
"Main components are now found at the design space. They act as a single source "
"of truth and can be worked on with their copies. This ensures consistency and "
"allows better control and synchronization."]]
[:div {:class (stl/css :info-block)}
[:div {:class (stl/css :info-icon)} deprecated-icon/v2-icon-2]
[:div {:class (stl/css :info-block-title)}
"Swap components"]
[:div {:class (stl/css :info-block-content)}
"Now, you can replace one component copy with another within your libraries. "
"The swap components functionality streamlines making changes, testing "
"variations, or updating elements without extensive manual adjustments."]]
[:div {:class (stl/css :info-block)}
[:div {:class (stl/css :info-icon)} deprecated-icon/v2-icon-3]
[:div {:class (stl/css :info-block-title)}
"Graphic assets no longer exist"]
[:div {:class (stl/css :info-block-content)}
"Graphic assets now disappear, so that all graphic assets become components. "
"This way, swapping between them is possible, and we avoid confusion about "
"what should go in each typology."]]
[:div {:class (stl/css :info-block)}
[:div {:class (stl/css :info-icon)} deprecated-icon/v2-icon-4]
[:div {:class (stl/css :info-block-title)}
"Main components page"]
[:div {:class (stl/css :info-block-content)}
"You might find that a new page called 'Main components' has appeared in "
"your file. On that page, you'll find all the main components that were "
"created in your files previously to this new version."]]]
[:div {:class (stl/css :info-bottom)}
[:> button* {:class (stl/css :primary-button)
:variant "primary"
:on-click handle-gotit-click} "I GOT IT"]]]]]))

View File

@ -354,79 +354,6 @@
padding-inline: var(--sp-xxs) px2rem(6);
}
// Modal Component v2 update
.modal-v2-info {
width: px2rem(664);
height: fit-content;
max-height: fit-content;
}
.modal-v2-title {
@include t.use-typography("headline-medium");
color: var(--modal-title-foreground-color);
}
.info-content {
display: grid;
grid-template-rows: repeat(4, 1fr);
margin-top: var(--sp-xxxl);
gap: var(--sp-xxl);
}
.info-block {
display: grid;
column-gap: var(--sp-xl);
grid-template:
"icon title" auto
"icon content" auto / auto 1fr;
}
.info-icon {
grid-area: icon;
width: px2rem(52);
height: px2rem(52);
margin-top: var(--sp-s);
border-radius: $br-circle;
background: var(--color-background-quaternary);
display: flex;
justify-content: center;
align-items: center;
svg {
width: $sz-32;
height: $sz-32;
fill: var(--icon-foreground-active);
}
}
.info-block-title {
@include t.use-typography("body-large");
grid-area: title;
color: var(--modal-title-foreground-color);
}
.info-block-content {
@include t.use-typography("body-medium");
grid-area: content;
color: var(--library-content-foreground-color);
}
.info-bottom {
display: flex;
justify-content: flex-end;
margin-block-start: var(--sp-xxl);
margin-inline-end: var(--sp-s);
}
.primary-button {
@include t.use-typography("headline-small");
padding: 0 var(--sp-l);
}
.sample-libraries-info {
@include t.use-typography("body-small");

View File

@ -395,7 +395,6 @@
multi-colors? (> (count selected) 1)
multi-assets? (or (seq (:components selected))
(seq (:graphics selected))
(seq (:typographies selected)))
groups (mf/with-memo [colors is-reverse-sort]

View File

@ -339,8 +339,7 @@
selected-full (into #{} (filter #(contains? selected (:id %))) components)
multi-components? (> (count selected) 1)
multi-assets? (or (seq (:graphics selected))
(seq (:colors selected))
multi-assets? (or (seq (:colors selected))
(seq (:typographies selected)))
selected-and-current (mf/with-memo [selected components current-component-id]

View File

@ -244,8 +244,6 @@
(st/emit! (dwu/start-undo-transaction undo-id))
(run! st/emit! (map delete-component
(:components selected)))
(run! st/emit! (map #(dwl/delete-media {:id %})
(:graphics selected)))
(run! st/emit! (map #(dwl/delete-color {:id %})
(:colors selected)))
(run! st/emit! (map #(dwl/delete-typography %)

View File

@ -328,7 +328,6 @@
multi-typographies? (> (count selected) 1)
multi-assets? (or (seq (:components selected))
(seq (:graphics selected))
(seq (:colors selected)))
open-groups-ref (mf/with-memo [open-status-ref]

View File

@ -35,7 +35,6 @@
{current-file-id
{:id current-file-id
:data {:id current-file-id
:options {:components-v2 true}
:components {}
:pages []
:pages-index {}}}}

View File

@ -1686,10 +1686,6 @@ msgstr ""
"El perfil que estàs convidant té els missatges de correu silenciats (per "
"informes de correu brossa o de retorns alts)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migració en curs"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Només la persona creadora de la versió la pot bloquejar"

View File

@ -998,10 +998,6 @@ msgstr ""
"Profil, který zvete, má ztlumené e-maily (zprávy o spamu nebo vysoké "
"nedoručitelnosti)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Probíhá migrace"
#: src/app/main/ui/auth/recovery.cljs:25, src/app/main/ui/settings/password.cljs:73
msgid "errors.password-invalid-confirmation"
msgstr "Potvrzovací heslo se musí shodovat"

View File

@ -1403,10 +1403,6 @@ msgstr ""
"In dem von Ihnen eingeladenen Profil sind E-Mails stummgeschaltet "
"(Spam-Berichte oder hohe Unzustellbarkeitsberichte)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migration wird durchgeführt"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Nur der Ersteller der Version kann sie sperren"

View File

@ -1679,10 +1679,6 @@ msgstr "Seems that this is not a valid image."
msgid "errors.member-is-muted"
msgstr "The profile you inviting has emails muted (spam reports or high bounces)."
#: src/app/main/errors.cljs:814
msgid "errors.migration-in-progress"
msgstr "Migration in progress"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Only the version creator can lock it"

View File

@ -1701,10 +1701,6 @@ msgstr ""
"El perfil que esta invitando tiene los emails silenciados (por reportes de "
"spam o alto índice de rebote)."
#: src/app/main/errors.cljs:814
msgid "errors.migration-in-progress"
msgstr "Migración en proceso"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Solo el creador de la versión puede bloquearla"

View File

@ -1663,10 +1663,6 @@ msgstr ""
"پروفایلی که دعوت می‌کنید ارسال ایمیل برایش غیرفعال شده است (گزارش‌های "
"هرزنامه یا برگشت‌های زیاد)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "مهاجرت در حال انجام است"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "فقط ایجادکنندهٔ نسخه می‌تواند آن را قفل کند"

View File

@ -1709,10 +1709,6 @@ msgstr ""
"L'adresse e-mail du profil que vous invitez est ignorée (signalée comme "
"spam ou taux de rebond élevé)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migration en cours"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Seul le créateur d'une version peut la verrouiller"

View File

@ -1575,10 +1575,6 @@ msgstr ""
"Le profil invité a tu ses courriels (selon les rapports de pourriels ou un "
"haut taux de rebond)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migration en cours"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Seul le créateur de la version peut la vérouiller"

View File

@ -1528,10 +1528,6 @@ msgstr "נראה כי זאת תמונה שגויה."
msgid "errors.member-is-muted"
msgstr "הודעות הדוא״ל לפרופיל שהזמנת מושתקות (דיווחים על דואר זבל או הרבה החזרות)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "מתבצעת הסבה"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "רק יוצר או יוצרת הגרסה יכולים לנעול אותה"

View File

@ -1247,10 +1247,6 @@ msgstr ""
"जिस प्रोफाइल को आप निमंत्रित कर रहे हैं उसके ईमेल म्यूट किए गए हैं (स्पैम "
"रिपोर्ट्स या उच्च बाउंस के कारण)।"
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "माइग्रेशन प्रगति पर है"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "केवल संस्करण निर्माता ही इसे लॉक कर सकता है"

View File

@ -995,10 +995,6 @@ msgstr ""
"Profil koji pozivaš ima isključen e-email (izvješća o neželjenoj pošti ili "
"veliki broj odbijanja)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migracija u tijeku"
#: src/app/main/ui/auth/recovery.cljs:25, src/app/main/ui/settings/password.cljs:73
msgid "errors.password-invalid-confirmation"
msgstr "Lozinka za potvrdu mora odgovarati"

View File

@ -1053,10 +1053,6 @@ msgstr ""
"Profil yang Anda undang membisukan surel (laporan spam atau lompatan "
"tinggi)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migrasi sedang berlangsung"
#: src/app/main/ui/auth/recovery.cljs:25, src/app/main/ui/settings/password.cljs:73
msgid "errors.password-invalid-confirmation"
msgstr "Kata sandi konfirmasi harus cocok"

View File

@ -1549,10 +1549,6 @@ msgstr ""
"Il profilo che stai invitando ha le email disattivate (rapporti di spam o "
"alti tassi di rimbalzo)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migrazione in corso"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Solo il creatore della versione può bloccarla"

View File

@ -1631,10 +1631,6 @@ msgstr "有効な画像ではないようです。"
msgid "errors.member-is-muted"
msgstr "招待しようとしているユーザーは、メールがミュートされています(スパム報告または配信エラーの多発)。"
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "移行中です"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "このバージョンをロックできるのは作成者のみです"

View File

@ -1265,10 +1265,6 @@ msgstr "유효한 이미지가 아닌 것 같습니다."
msgid "errors.member-is-muted"
msgstr "초대하려는 프로필의 이메일 수신이 거부되었습니다(스팸 신고 또는 높은 반송률)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "마이그레이션 진행 중"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "버전 생성자만 잠글 수 있습니다"

View File

@ -1183,10 +1183,6 @@ msgstr ""
"Uzaicinātajam profilam ir apklusināta e-pasta saņemšana (ziņojumi par "
"surogātpastu vai daudz atlēcienu)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Notiek pārcelšana"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Tikai versijas izveidotājs var to aizslēgt"

View File

@ -1685,10 +1685,6 @@ msgstr ""
"Het profiel dat je uitnodigt, heeft e-mails gedempt (spammeldingen of hoge "
"bounces)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migratie aan de gang"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Alleen de maker van de versie kan het vergrendelen"

View File

@ -1155,10 +1155,6 @@ msgstr ""
"O perfil que você está convidando tem e-mails silenciados (relatos de spam "
"ou altas devoluções)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migração em progresso"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Somente o criador da versão pode bloqueá-la"

View File

@ -1003,10 +1003,6 @@ msgstr ""
"O perfil que estás a convidar tem e-mails silenciados (relatórios de spam "
"ou devoluções altas)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migração em progresso"
#: src/app/main/ui/auth/recovery.cljs:25, src/app/main/ui/settings/password.cljs:73
msgid "errors.password-invalid-confirmation"
msgstr "A palavra-passe de confirmação tem de corresponder"

View File

@ -1170,10 +1170,6 @@ msgstr ""
"Profilul pe care încerci să îl inviți este dezactivat (din cauza "
"rapoartelor spam sau inactivitate)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migrație în progres"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Doar creatorul versiunii poate bloca"

View File

@ -1317,10 +1317,6 @@ msgstr "Неверное медиа."
msgid "errors.member-is-muted"
msgstr "Невозможно пригласить адресата с недоступным адресом электронной почты."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Миграция в процессе"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Только создатель версии может ее заблокировать"

View File

@ -1670,10 +1670,6 @@ msgstr ""
"Den profil du bjuder in har e-postmeddelanden som är avstängda "
"(skräppostrapporter eller höga studsar)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Migrering pågår"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Endast skaparen av versionen kan låsa den"

View File

@ -1672,10 +1672,6 @@ msgstr ""
"Davet ettiğiniz profilin e-posta adresine ait çok fazla geri dönme raporu "
"var veya spam olarak bildirilmiş."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Geçiş devam ediyor"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Yalnızca sürüm oluşturucu onu kilitleyebilir"

View File

@ -1457,10 +1457,6 @@ msgstr ""
"Електронна пошта профілю, який Ви намагаєтесь запросити, має приглушення "
"листів (скарги на спам або постійне пересилання)."
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "Міграція триває"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "Тільки власник версії може заблокувати її"

View File

@ -1380,10 +1380,6 @@ msgstr "该图片好像不可用。"
msgid "errors.member-is-muted"
msgstr "受邀用户已停用邮件通知(曾举报垃圾邮件或多次发生退信)。"
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "迁移正在进行中"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "只有版本创建者可以锁定"

View File

@ -1579,10 +1579,6 @@ msgstr "這似乎不是有效的圖片。"
msgid "errors.member-is-muted"
msgstr "您邀請的使用者已因垃圾郵件檢舉或退信率過高而暫停接收電子郵件。"
#: src/app/main/errors.cljs:805
msgid "errors.migration-in-progress"
msgstr "正在進行資料遷移"
#: src/app/main/errors.cljs:707
msgid "errors.only-creator-can-lock"
msgstr "只有此版本的建立者可以鎖定此版本"