diff --git a/backend/src/app/features/fdata.clj b/backend/src/app/features/fdata.clj index 3ec5fdfb5..baa63f693 100644 --- a/backend/src/app/features/fdata.clj +++ b/backend/src/app/features/fdata.clj @@ -62,6 +62,12 @@ {:id id :file-id file-id} {::sql/columns [:content] ::db/check-deleted false})] + + (l/trc :hint "load pointer" + :file-id (str file-id) + :id (str id) + :found (some? content)) + (when-not content (ex/raise :type :internal :code :fragment-not-found diff --git a/backend/src/app/srepl/helpers.clj b/backend/src/app/srepl/helpers.clj index 010a0aa7a..38ea61dd8 100644 --- a/backend/src/app/srepl/helpers.clj +++ b/backend/src/app/srepl/helpers.clj @@ -35,15 +35,18 @@ (defn get-file "Get the migrated data of one file." - ([id] (get-file (or *system* main/system) id)) - ([system id] + ([id] (get-file (or *system* main/system) id nil)) + ([system id & {:keys [raw?] :as opts}] (db/run! system (fn [system] - (binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)] - (-> (files/get-file system id :migrate? false) - (update :data feat.fdata/process-pointers deref) - (update :data feat.fdata/process-objects (partial into {})) - (fmg/migrate-file))))))) + (let [file (files/get-file system id :migrate? false)] + (if raw? + file + (binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)] + (-> file + (update :data feat.fdata/process-pointers deref) + (update :data feat.fdata/process-objects (partial into {})) + (fmg/migrate-file))))))))) (defn update-file! [system {:keys [id] :as file}] @@ -166,7 +169,7 @@ (fsnap/take-file-snapshot! system {:file-id file-id :label label})) (let [conn (db/get-connection system) - file (get-file system file-id) + file (get-file system file-id opts) libs (when with-libraries? (->> (files/get-file-libraries conn file-id) (into [file] (map (fn [{:keys [id]}] diff --git a/backend/src/app/srepl/main.clj b/backend/src/app/srepl/main.clj index 17df79a9a..2f538d6f6 100644 --- a/backend/src/app/srepl/main.clj +++ b/backend/src/app/srepl/main.clj @@ -429,7 +429,9 @@ (try (l/trc :hint "process:file:start" :file-id (str file-id) :index idx) (let [system (assoc main/system ::db/rollback rollback?)] - (db/tx-run! system h/process-file! file-id update-fn opts)) + (db/tx-run! system (fn [system] + (binding [h/*system* system] + (h/process-file! system file-id update-fn opts))))) (catch Throwable cause (l/wrn :hint "unexpected error on processing file (skiping)" diff --git a/backend/src/app/tasks/file_gc.clj b/backend/src/app/tasks/file_gc.clj index 29c07f78b..ed7815f68 100644 --- a/backend/src/app/tasks/file_gc.clj +++ b/backend/src/app/tasks/file_gc.clj @@ -65,19 +65,8 @@ :features (:features file) :version (:version file) :data (:data file)} - {:id id}))) - -(defn- process-file! - [cfg file] - (try - (let [file (decode-file cfg file) - file (clean-file! cfg file)] - (cfv/validate-file-schema! file) - (update-file! cfg file)) - (catch Throwable cause - (l/err :hint "error on cleaning file (skiping)" - :file-id (str (:id file)) - :cause cause)))) + {:id id} + {::db/return-keys true}))) (def ^:private sql:get-candidates @@ -118,13 +107,15 @@ unused (->> (db/exec! conn [sql:mark-file-media-object-deleted id ids]) (into #{} (map :id)))] + (l/dbg :hint "clean" :rel "file-media-object" :file-id (str id) :total (count unused)) + (doseq [id unused] (l/trc :hint "mark deleted" :rel "file-media-object" :id (str id) :file-id (str id))) - [(count unused) file])) + file)) (def ^:private sql:mark-file-object-thumbnails-deleted "UPDATE file_tagged_object_thumbnail @@ -149,13 +140,15 @@ unused (->> (db/exec! conn [sql:mark-file-object-thumbnails-deleted file-id ids]) (into #{} (map :object-id)))] + (l/dbg :hint "clean" :rel "file-object-thumbnail" :file-id (str file-id) :total (count unused)) + (doseq [object-id unused] (l/trc :hint "mark deleted" :rel "file-tagged-object-thumbnail" :object-id object-id :file-id (str file-id))) - [(count unused) file])) + file)) (def ^:private sql:mark-file-thumbnails-deleted "UPDATE file_thumbnail @@ -168,13 +161,15 @@ (let [unused (->> (db/exec! conn [sql:mark-file-thumbnails-deleted id revn]) (into #{} (map :revn)))] + (l/dbg :hint "clean" :rel "file-thumbnail" :file-id (str id) :total (count unused)) + (doseq [revn unused] (l/trc :hint "mark deleted" :rel "file-thumbnail" :revn revn :file-id (str id))) - [(count unused) file])) + file)) (def ^:private sql:get-files-for-library @@ -230,7 +225,9 @@ file (update file :data process-fdata unused)] - [(count unused) file])) + + (l/dbg :hint "clean" :rel "components" :file-id (str file-id) :total (count unused)) + file)) (def ^:private sql:get-changes "SELECT id, data FROM file_change @@ -242,47 +239,52 @@ SET deleted_at = now() WHERE file_id = ? AND id != ALL(?::uuid[]) + AND deleted_at IS NULL RETURNING id") +(def ^:private xf:collect-pointers + (comp (map :data) + (map blob/decode) + (mapcat feat.fdata/get-used-pointer-ids))) + (defn- clean-data-fragments! - [{:keys [::db/conn]} {:keys [id data] :as file}] - (let [used (->> (db/cursor conn [sql:get-changes id]) - (into (feat.fdata/get-used-pointer-ids data) - (comp (map :data) - (map blob/decode) - (mapcat feat.fdata/get-used-pointer-ids)))) + [{:keys [::db/conn]} {:keys [id] :as file}] + (let [used (into #{} xf:collect-pointers + (cons file (db/cursor conn [sql:get-changes id]))) unused (let [ids (db/create-array conn "uuid" used)] (->> (db/exec! conn [sql:mark-deleted-data-fragments id ids]) (into #{} (map :id))))] + (l/dbg :hint "clean" :rel "file-data-fragment" :file-id (str id) :total (count unused)) (doseq [id unused] (l/trc :hint "mark deleted" :rel "file-data-fragment" :id (str id) - :file-id (str id))) - - [(count unused) file])) - -(defn- clean-file! - [cfg {:keys [id] :as file}] - (let [[n1 file] (clean-file-media! cfg file) - [n2 file] (clean-file-thumbnails! cfg file) - [n3 file] (clean-file-object-thumbnails! cfg file) - [n4 file] (clean-deleted-components! cfg file) - [n5 file] (clean-data-fragments! cfg file)] - - (l/dbg :hint "file clened" - :file-id (str id) - :modified-at (dt/format-instant (:modified-at file)) - :media-objects n1 - :thumbnails n2 - :object-thumbnails n3 - :components n4 - :data-fragments n5) + :file-id (str id))))) +(defn- clean-media! + [cfg file] + (let [file (->> file + (clean-file-media! cfg) + (clean-file-thumbnails! cfg) + (clean-file-object-thumbnails! cfg) + (clean-deleted-components! cfg))] + (cfv/validate-file-schema! file) file)) +(defn- process-file! + [cfg file] + (try + (let [file (decode-file cfg file) + file (clean-media! cfg file) + file (update-file! cfg file)] + (clean-data-fragments! cfg file)) + (catch Throwable cause + (l/err :hint "error on cleaning file (skiping)" + :file-id (str (:id file)) + :cause cause)))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; HANDLER ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/backend/src/app/util/pointer_map.clj b/backend/src/app/util/pointer_map.clj index f5933ecd6..16ce73bb0 100644 --- a/backend/src/app/util/pointer_map.clj +++ b/backend/src/app/util/pointer_map.clj @@ -37,7 +37,6 @@ (:require [app.common.fressian :as fres] - [app.common.logging :as l] [app.common.transit :as t] [app.common.uuid :as uuid] [app.util.time :as dt] @@ -78,8 +77,6 @@ IPointerMap (load! [_] - (l/trace :hint "pointer-map:load" :id (str id)) - (when-not *load-fn* (throw (UnsupportedOperationException. "load is not supported when *load-fn* is not bind"))) diff --git a/backend/src/app/worker.clj b/backend/src/app/worker.clj index 3a6bfe897..5c63ecfa0 100644 --- a/backend/src/app/worker.clj +++ b/backend/src/app/worker.clj @@ -683,7 +683,6 @@ deleted (when dedupe (-> (db/exec-one! conn [sql:remove-not-started-tasks task queue label]) :next.jdbc/update-count))] - (l/trc :hint "submit task" :name task :queue queue diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 3a2ab58b2..120d22290 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -326,7 +326,9 @@ reset-modifiers? (and (gpo/axis-aligned? parent-bounds) (gpo/axis-aligned? child-bounds) - (gpo/axis-aligned? transformed-parent-bounds)) + (gpo/axis-aligned? transformed-parent-bounds) + (not= :scale constraints-h) + (not= :scale constraints-v)) modifiers (if reset-modifiers? diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index 92f2969e0..2034ab58c 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -311,6 +311,19 @@ [new-root-shape (map remap-frame-id new-shapes) updated-shapes])) +(defn remove-swap-keep-attrs + "Remove flex children properties except the fit-content for flex layouts. These are properties + that we don't have to propagate to copies but will be respected when swapping components" + [shape] + (let [layout-item-h-sizing (when (and (ctl/flex-layout? shape) (ctl/auto-width? shape)) :auto) + layout-item-v-sizing (when (and (ctl/flex-layout? shape) (ctl/auto-height? shape)) :auto)] + (-> shape + (d/without-keys ctk/swap-keep-attrs) + (cond-> (some? layout-item-h-sizing) + (assoc :layout-item-h-sizing layout-item-h-sizing)) + (cond-> (some? layout-item-v-sizing) + (assoc :layout-item-v-sizing layout-item-v-sizing))))) + (defn make-component-instance "Generate a new instance of the component inside the given container. @@ -331,7 +344,7 @@ (-> (get-shape component-page (:main-instance-id component)) (assoc :parent-id nil) ;; On v2 we force parent-id to nil in order to behave like v1 (assoc :frame-id uuid/zero) - (d/without-keys ctk/swap-keep-attrs)) + (remove-swap-keep-attrs)) (get-shape component (:id component))) orig-pos (gpt/point (:x component-shape) (:y component-shape)) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 15622d4dd..80e38ab3e 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -910,6 +910,11 @@ (mapcat #(cfh/get-children-with-self objects (:id %))) (map :id)) + child-heads + (->> moving-shapes-ids + (mapcat #(ctn/get-child-heads objects %)) + (map :id)) + changes (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) @@ -921,10 +926,7 @@ (pcb/update-shapes moving-shapes-children-ids #(dissoc % :component-root))) ;; Add component-root property when moving a component outside a component (cond-> (not (ctn/get-instance-root objects frame)) - (pcb/update-shapes moving-shapes-ids (fn [shape] - (if (ctk/instance-head? shape) - (assoc shape :component-root true) - shape)))) + (pcb/update-shapes child-heads #(assoc % :component-root true))) (pcb/update-shapes moving-shapes-ids #(cond-> % (cfh/frame-shape? %) (assoc :hide-in-viewer true))) (pcb/update-shapes shape-ids-to-detach ctk/detach-shape) (pcb/change-parent frame-id moving-shapes drop-index) diff --git a/frontend/src/app/main/ui/comments.scss b/frontend/src/app/main/ui/comments.scss index 51e6ddadb..c41dcd306 100644 --- a/frontend/src/app/main/ui/comments.scss +++ b/frontend/src/app/main/ui/comments.scss @@ -108,6 +108,7 @@ word-wrap: break-word; overflow-wrap: break-word; hyphens: auto; + white-space: pre-wrap; } .replies { diff --git a/frontend/src/app/main/ui/viewer/inspect/code.cljs b/frontend/src/app/main/ui/viewer/inspect/code.cljs index c1e5ebcd2..bceac31ad 100644 --- a/frontend/src/app/main/ui/viewer/inspect/code.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/code.cljs @@ -189,7 +189,14 @@ (mf/use-fn (mf/deps style-code markup-code images-data) (fn [] - (wapi/write-to-clipboard (gen-all-code style-code markup-code images-data)))) + (wapi/write-to-clipboard (gen-all-code style-code markup-code images-data)) + (let [origin (if (= :workspace from) + "workspace" + "viewer")] + (st/emit! (ptk/event ::ev/event + {::ev/name "copy-inspect-code" + ::ev/origin origin + :type "all"}))))) ;;handle-open-review ;;(mf/use-fn diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index 564093850..ddbfe354a 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -239,6 +239,7 @@ [:button {:class (stl/css :item-button) :type "button" + :title (tr "workspace.libraries.unlink-library-btn") :data-library-id (dm/str id) :on-click unlink-library} detach-icon]])]] @@ -270,6 +271,7 @@ :typography-count typography-count}])]] [:button {:class (stl/css :item-button-shared) :data-library-id (dm/str id) + :title (tr "workspace.libraries.shared-library-btn") :on-click link-library} add-icon]])] diff --git a/frontend/src/app/main/ui/workspace/libraries.scss b/frontend/src/app/main/ui/workspace/libraries.scss index 6d5143d73..0762d3b48 100644 --- a/frontend/src/app/main/ui/workspace/libraries.scss +++ b/frontend/src/app/main/ui/workspace/libraries.scss @@ -182,6 +182,11 @@ margin-block-start: $s-16; } +.libraries-updates-column { + display: grid; + gap: $s-4; +} + .libraries-updates-item { @include bodyLargeTypography; display: grid; diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 70e46664a..f4bd1f9d3 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -155,7 +155,8 @@ task-ref (mf/use-ref nil) on-load (mf/use-fn (fn [] - (check-thumbnail-size (mf/ref-val imposter-ref) bounds file-id page-id frame-id) + ;; We need to check if this is the culprit of the thumbnail regeneration. + ;; (check-thumbnail-size (mf/ref-val imposter-ref) bounds file-id page-id frame-id) (mf/set-ref-val! tries-ref 0) (reset! imposter-loaded true))) on-error (mf/use-fn diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index da7ed67fe..b3f755fc5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -168,6 +168,7 @@ :placeholder (tr "workspace.assets.search")} [:button {:on-click on-open-menu + :title (tr "workspace.assets.filter") :class (stl/css-case :section-button true :opened menu-open?)} i/filter-icon]] @@ -184,6 +185,7 @@ :options options :workspace? true}] [:button {:class (stl/css :sort-button) + :title (tr "workspace.assets.sort") :on-click toggle-ordering} (if reverse-sort? i/asc-sort diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 4ab174a38..debc36252 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -10,6 +10,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] + [app.common.types.shape :as cts] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] [app.main.refs :as refs] @@ -147,7 +148,10 @@ (or (empty? filters) (and (contains? filters :component) (contains? shape :component-id)) - (let [direct-filters (into #{} (filter #{:frame :rect :circle :path :bool :image :text}) filters)] + (and (contains? filters :image) + (some? (cts/has-images? shape))) + + (let [direct-filters (into #{} (filter #{:frame :rect :circle :path :bool :text}) filters)] (contains? direct-filters (:type shape))) (and (contains? filters :group) (and (cfh/group-shape? shape) @@ -166,7 +170,6 @@ :filters #{} :num-items 100}) state (deref state*) - current-filters (:filters state) current-items (:num-items state) current-search (:search-text state) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs index a892a87e0..f605ac544 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs @@ -59,7 +59,7 @@ [layer-ids layer-values] (get-attrs [shape] objects :layer) [constraint-ids constraint-values] (get-attrs [shape] objects :constraint) [fill-ids fill-values] (get-attrs [shape] objects :fill) - [shadow-ids shadow-values] (get-attrs [shape] objects :shadow) + [shadow-ids _] (get-attrs [shape] objects :shadow) [blur-ids blur-values] (get-attrs [shape] objects :blur) [stroke-ids stroke-values] (get-attrs [shape] objects :stroke) [text-ids text-values] (get-attrs [shape] objects :text) @@ -108,7 +108,7 @@ :shared-libs shared-libs}] (when-not (empty? shadow-ids) - [:& shadow-menu {:type type :ids shadow-ids :values shadow-values}]) + [:& shadow-menu {:type type :ids ids :values (select-keys shape [:shadow])}]) (when-not (empty? blur-ids) [:& blur-menu {:type type :ids blur-ids :values blur-values}]) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index a0ad7a087..b94cd8fb4 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -3255,6 +3255,14 @@ msgstr "Rename group" msgid "workspace.assets.search" msgstr "Search assets" +#: src/app/main/ui/workspace/sidebar/assets.cljs +msgid "workspace.assets.filter" +msgstr "Filter" + +#: src/app/main/ui/workspace/sidebar/assets.cljs +msgid "workspace.assets.sort" +msgstr "Sort" + #: src/app/main/ui/workspace/sidebar/assets.cljs msgid "workspace.assets.selected-count" msgid_plural "workspace.assets.selected-count" @@ -3611,6 +3619,14 @@ msgstr "Search shared libraries" msgid "workspace.libraries.shared-libraries" msgstr "SHARED LIBRARIES" +#: src/app/main/ui/workspace/libraries.cljs +msgid "workspace.libraries.shared-library-btn" +msgstr "Connect library" + +#: src/app/main/ui/workspace/libraries.cljs +msgid "workspace.libraries.unlink-library-btn" +msgstr "Disconnect library" + #: src/app/main/ui/workspace/libraries.cljs msgid "workspace.libraries.loading" msgstr "Loading…" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 30b388b04..cec823c04 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -3312,6 +3312,14 @@ msgstr "Renombrar grupo" msgid "workspace.assets.search" msgstr "Buscar recursos" +#: src/app/main/ui/workspace/sidebar/assets.cljs +msgid "workspace.assets.filter" +msgstr "Filtrar" + +#: src/app/main/ui/workspace/sidebar/assets.cljs +msgid "workspace.assets.sort" +msgstr "Ordenar" + #: src/app/main/ui/workspace/sidebar/assets.cljs msgid "workspace.assets.selected-count" msgid_plural "workspace.assets.selected-count" @@ -3675,6 +3683,14 @@ msgstr "Buscar bibliotecas compartidas" msgid "workspace.libraries.shared-libraries" msgstr "BIBLIOTECAS COMPARTIDAS" +#: src/app/main/ui/workspace/libraries.cljs +msgid "workspace.libraries.shared-library-btn" +msgstr "Conectar biblioteca" + +#: src/app/main/ui/workspace/libraries.cljs +msgid "workspace.libraries.unlink-library-btn" +msgstr "Desconectar biblioteca" + #: src/app/main/ui/workspace/sidebar/options/menus/text.cljs msgid "workspace.libraries.text.multiple-typography" msgstr "Varias tipografías"