Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh
2025-07-29 14:06:53 +02:00
22 changed files with 178 additions and 123 deletions

View File

@@ -68,6 +68,8 @@
- Fix problem when changing between flex/grid layout [Taiga #11625](https://tree.taiga.io/project/penpot/issue/11625)
- Fix opacity on stroke gradients [Taiga #11646](https://tree.taiga.io/project/penpot/issue/11646)
- Fix change from gradient to solid color [Taiga #11648](https://tree.taiga.io/project/penpot/issue/11648)
- Fix the context menu always closes after any action [Taiga #11624](https://tree.taiga.io/project/penpot/issue/11624)
- Fix font selector highlight inconsistency when using keyboard navigation [Taiga #11668](https://tree.taiga.io/project/penpot/issue/11668)
## 2.8.1 (Unreleased)
@@ -75,6 +77,7 @@
- Fix unexpected exception on processing old texts [Github #6889](https://github.com/penpot/penpot/pull/6889)
- Fix UI theme selection from main menu [Taiga #11567](https://tree.taiga.io/project/penpot/issue/11567)
- Add missing migration information to file snapshots [Github #686](https://github.com/penpot/penpot/pull/6864)
## 2.8.0

View File

@@ -10,18 +10,19 @@
[app.config :as cf]
[app.util.time :as dt]))
(def ^:private canceled-status
#{"canceled" "unpaid"})
(defn get-deletion-delay
"Calculate the next deleted-at for a resource (file, team, etc) in function
of team settings"
[team]
(if-let [subscription (get team :subscription)]
(if-let [{:keys [type status]} (get team :subscription)]
(cond
(and (= (:type subscription) "unlimited")
(= (:status subscription) "active"))
(and (= "unlimited" type) (not (contains? canceled-status status)))
(dt/duration {:days 30})
(and (= (:type subscription) "enterprise")
(= (:status subscription) "active"))
(and (= "enterprise" type) (not (contains? canceled-status status)))
(dt/duration {:days 90})
:else

View File

@@ -438,7 +438,10 @@
:fn (mg/resource "app/migrations/sql/0138-mod-file-data-fragment-table.sql")}
{:name "0139-mod-file-change-table.sql"
:fn (mg/resource "app/migrations/sql/0139-mod-file-change-table.sql")}])
:fn (mg/resource "app/migrations/sql/0139-mod-file-change-table.sql")}
{:name "0140-mod-file-change-table.sql"
:fn (mg/resource "app/migrations/sql/0140-mod-file-change-table.sql")}])
(defn apply-migrations!
[pool name migrations]

View File

@@ -0,0 +1,2 @@
ALTER TABLE file_change
ADD COLUMN migrations text[];

View File

@@ -8,6 +8,7 @@
(:require
[app.binfile.common :as bfc]
[app.common.exceptions :as ex]
[app.common.files.migrations :as fmg]
[app.common.logging :as l]
[app.common.schema :as sm]
[app.common.uuid :as uuid]
@@ -15,6 +16,7 @@
[app.db :as db]
[app.db.sql :as-alias sql]
[app.features.fdata :as feat.fdata]
[app.features.file-migrations :refer [reset-migrations!]]
[app.main :as-alias main]
[app.msgbus :as mbus]
[app.rpc :as-alias rpc]
@@ -27,6 +29,13 @@
[app.util.time :as dt]
[cuerdas.core :as str]))
(defn decode-row
[{:keys [migrations] :as row}]
(when row
(cond-> row
(some? migrations)
(assoc :migrations (db/decode-pgarray migrations)))))
(def sql:get-file-snapshots
"WITH changes AS (
SELECT id, label, revn, created_at, created_by, profile_id
@@ -74,10 +83,7 @@
(assert (#{:system :user :admin} created-by)
"expected valid keyword for created-by")
(let [conn
(db/get-connection cfg)
created-by
(let [created-by
(name created-by)
deleted-at
@@ -101,12 +107,15 @@
(blob/encode (:data file))
features
(db/encode-pgarray (:features file) conn "text")]
(into-array (:features file))
(l/debug :hint "creating file snapshot"
:file-id (str (:id file))
:id (str snapshot-id)
:label label)
migrations
(into-array (:migrations file))]
(l/dbg :hint "creating file snapshot"
:file-id (str (:id file))
:id (str snapshot-id)
:label label)
(db/insert! cfg :file-change
{:id snapshot-id
@@ -114,6 +123,7 @@
:data data
:version (:version file)
:features features
:migrations migrations
:profile-id profile-id
:file-id (:id file)
:label label
@@ -159,7 +169,17 @@
{:file-id file-id
:id snapshot-id}
{::db/for-share true})
(feat.fdata/resolve-file-data cfg))]
(feat.fdata/resolve-file-data cfg)
(decode-row))
;; If snapshot has tracked applied migrations, we reuse them,
;; if not we take a safest set of migrations as starting
;; point. This is because, at the time of implementing
;; snapshots, migrations were not taken into account so we
;; need to make this backward compatible in some way.
file (assoc file :migrations
(or (:migrations snapshot)
(fmg/generate-migrations-from-version 67)))]
(when-not snapshot
(ex/raise :type :not-found
@@ -180,12 +200,16 @@
:label (:label snapshot)
:snapshot-id (str (:id snapshot)))
;; If the file was already offloaded, on restring the snapshot
;; we are going to replace the file data, so we need to touch
;; the old referenced storage object and avoid possible leaks
;; If the file was already offloaded, on restoring the snapshot we
;; are going to replace the file data, so we need to touch the old
;; referenced storage object and avoid possible leaks
(when (feat.fdata/offloaded? file)
(sto/touch-object! storage (:data-ref-id file)))
;; In the same way, on reseting the file data, we need to restore
;; the applied migrations on the moment of taking the snapshot
(reset-migrations! conn file)
(db/update! conn :file
{:data (:data snapshot)
:revn (inc (:revn file))
@@ -253,7 +277,7 @@
:deleted-at nil}
{:id snapshot-id}
{::db/return-keys true})
(dissoc :data :features)))
(dissoc :data :features :migrations)))
(defn- get-snapshot
"Get a minimal snapshot from database and lock for update"

View File

@@ -80,7 +80,7 @@
(update :migrations set/union diff)
(vary-meta assoc ::migrated (not-empty diff)))))
(defn- generate-migrations-from-version
(defn generate-migrations-from-version
"A function that generates new format migration from the old,
version based migration system"
[version]

View File

@@ -11,6 +11,7 @@
[app.common.files.helpers :as cfh]
[app.common.geom.shapes :as gsh]
[app.common.logic.variant-properties :as clvp]
[app.common.text :as ct]
[app.common.types.component :as ctk]
[app.common.types.container :as ctn]
[app.common.types.pages-list :as ctpl]

View File

@@ -125,7 +125,7 @@ RUN set -ex; \
COPY --from=build /opt/jre /opt/jre
COPY --from=build /opt/node /opt/node
COPY --from=penpotapp/imagemagick:7.1.1-47 /opt/imagick /opt/imagick
COPY --from=penpotapp/imagemagick:7.1.2-0 /opt/imagick /opt/imagick
COPY --chown=penpot:penpot ./bundle-backend/ /opt/penpot/backend/
USER penpot:penpot

View File

@@ -205,6 +205,10 @@ title: 10· Design Tokens
<h4>Y Position (dimension)</h4>
<p>The Y property specifies the position of the element on the Y axis of the canvas.</p>
<h3 id="design-tokens-font-size">Font Size</h3>
<p>Font size tokens allow you to define and standardize font-size values across your design system. These tokens can be applied to the <strong>font-size</strong> property in text layers, ensuring consistent typography throughout your designs.</p>
<p class="advice">Font size token values are always computed as <strong>px</strong> (pixels).</p>
<h3 id="design-tokens-opacity">Opacity</h3>
<p>Opacity tokens allow you to define the opacity of a layer, ranging from fully opaque to fully transparent.</p>
<p>Opacity tokens can be applied to any design element that supports transparency. You can use any decimal value between 0 and 1 to set varying levels of opacity or you can use any value between 0 and 100 with <strong>`%`</strong> sign at the end of the value. For example, you can use <strong>45%</strong> which would resolve to <strong>.45</strong>.</p>
@@ -378,7 +382,15 @@ title: 10· Design Tokens
</ol>
<h3 id="design-tokens-import-options">Import Options</h3>
<h4>Single file</h4>
<h4>ZIP file</h4>
<p>You can import tokens from a <strong>.zip</strong> file. This file can either contain a single JSON file or a folder structure with multiple files. The ZIP import option provides flexibility for organizing your tokens before importing them into Penpot.</p>
<ul>
<li>If the ZIP contains a single JSON file, it will be imported as a single set of tokens.</li>
<li>If the ZIP contains a folder structure, each file and folder will be interpreted as separate token sets, following the same rules as the multifile import.</li>
</ul>
<h4>Single JSON file</h4>
<p>You can import a JSON file comprising all tokens, token sets and token themes.</p>
<p>When importing a single file, the first-level keys of the json file will be interpreted as the set name.</p>

View File

@@ -34,7 +34,13 @@ desc: Master layer basics with Penpot's user guide! Learn to create, manipulate,
<p>Layers are displayed from the bottom to the top of the layer stack, with layers above on the stack being shown on top in the image.</p>
<h2 id="hide-lock">Hide and lock layers</h2>
<p>Click on the eye icon to change the visibility of a layer. Click on the lock icon to lock or unlock a layer. A locked layer can not be modified.</p>
<h3>Hide and show layers</h3>
<p>You can control the visibility of any layer by clicking the eye icon next to it in the Layers panel. When a layer is hidden, it will not appear on the canvas, but you can still select it in the Layers panel, move its order, or modify its properties. The eye icon always indicates whether a layer is visible or hidden, making it easy to manage complex designs.</p>
<h3>Lock and unlock layers</h3>
<p>Locking a layer helps prevent accidental changes or movement on the canvas. When a layer is locked, it cannot be moved or edited directly in the canvas area. However, you can still select a locked layer in the Layers panel and adjust its properties, such as color, effects, or name. The lock icon next to the layers name shows its locked status, helping you keep your design organized and protected.</p>
<figure>
<video title="Layers hide and lock" muted="" playsinline="" controls="" width="auto" poster="/img/layers/layers-hide-lock.webp" height="auto">
<source src="/img/layers/layers-hide-lock.mp4" type="video/mp4">

View File

@@ -142,6 +142,11 @@ a design.</p>
<source src="/img/objects/text-create.mp4" type="video/mp4">
</video>
</figure>
<p><strong>Tips for resizing</strong></p>
<ul>
<li>Double-click on the right side of the bounding box to set the resize setting to auto-width.</li>
<li>Double-click on the bottom side of the bounding box to set the resize setting to auto-height.</li>
</ul>
<h3>Edit and style text content</h3>
<p>Press <kbd>Enter</kbd> with a text layer selected to start editing the text content. You can style parts of the text content as rich text.</p>
<figure>

View File

@@ -1098,15 +1098,24 @@
(when (seq (:redo-changes changes))
(rx/of (dch/commit-changes changes)))
(when-not (empty? updated-frames)
(rx/merge
(rx/of (ptk/data-event :layout/update {:ids (map :id updated-frames) :undo-group undo-group}))
(->> (rx/from updated-frames)
(rx/mapcat
(fn [shape]
(rx/of
(dwt/clear-thumbnail file-id (:page-id shape) (:id shape) "frame")
(when-not (= (:frame-id shape) uuid/zero)
(dwt/clear-thumbnail file-id (:page-id shape) (:frame-id shape) "frame"))))))))
(let [frames-by-page (->> updated-frames
(group-by :page-id))]
(rx/merge
;; Emit one layout/update event for each page
(rx/from
(map (fn [[page-id frames]]
(ptk/data-event :layout/update
{:page-id page-id
:ids (map :id frames)
:undo-group undo-group}))
frames-by-page))
(->> (rx/from updated-frames)
(rx/mapcat
(fn [shape]
(rx/of
(dwt/clear-thumbnail file-id (:page-id shape) (:id shape) "frame")
(when-not (= (:frame-id shape) uuid/zero)
(dwt/clear-thumbnail file-id (:page-id shape) (:frame-id shape) "frame")))))))))
(when (not= file-id library-id)
;; When we have just updated the library file, give some time for the

View File

@@ -131,11 +131,12 @@
;; they are process together. It will get a better performance.
(rx/buffer-time 100)
(rx/filter #(d/not-empty? %))
(rx/map
(rx/mapcat
(fn [data]
(let [page-id (->> data (keep :page-id) first)
ids (reduce #(into %1 (:ids %2)) #{} data)]
(update-layout-positions {:page-id page-id :ids ids}))))
(->> (group-by :page-id data)
(map (fn [[page-id items]]
(let [ids (reduce #(into %1 (:ids %2)) #{} items)]
(update-layout-positions {:page-id page-id :ids ids})))))))
(rx/take-until stopper))))))
(defn finalize-shape-layout

View File

@@ -304,7 +304,6 @@
(when (string? value)
(generate-text-shape-update {:text-transform value} shape-ids page-id))))
;; Events to apply / unapply tokens to shapes ------------------------------------------------------------
(defn apply-token

View File

@@ -75,7 +75,7 @@
[:> cta-power-up*
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
:top-description (tr "subscription.dashboard.power-up.unlimited-plan")
:bottom-description (tr "subscription.dashboard.power-up.unlimited.bottom", subscription-href)
:bottom-description (tr "subscription.dashboard.power-up.unlimited.bottom-text", subscription-href)
:has-dropdown true}])
"enterprise"

View File

@@ -365,17 +365,17 @@
[:> plan-card* {:card-title (tr "subscription.settings.enterprise-trial")
:card-title-icon i/character-e
:benefits-title (tr "subscription.settings.benefits.all-professional-benefits")
:benefits [(tr "subscription.settings.enterprise.security"),
:benefits [(tr "subscription.settings.enterprise.unlimited-storage"),
(tr "subscription.settings.enterprise.capped-bill"),
(tr "subscription.settings.enterprise.unlimited-storage")]
(tr "subscription.settings.enterprise.autosave")]
:cta-text (tr "subscription.settings.manage-your-subscription")
:cta-link go-to-payments}]
[:> plan-card* {:card-title (tr "subscription.settings.enterprise")
:card-title-icon i/character-e
:benefits-title (tr "subscription.settings.benefits.all-professional-benefits")
:benefits [(tr "subscription.settings.enterprise.security"),
:benefits [(tr "subscription.settings.enterprise.unlimited-storage"),
(tr "subscription.settings.enterprise.capped-bill"),
(tr "subscription.settings.enterprise.unlimited-storage")]
(tr "subscription.settings.enterprise.autosave")]
:cta-text (tr "subscription.settings.manage-your-subscription")
:cta-link go-to-payments}]))
@@ -425,9 +425,9 @@
:price-value "$950"
:price-period (tr "subscription.settings.price-organization-month")
:benefits-title (tr "subscription.settings.benefits.all-unlimited-benefits")
:benefits [(tr "subscription.settings.enterprise.security"),
:benefits [(tr "subscription.settings.enterprise.unlimited-storage"),
(tr "subscription.settings.enterprise.capped-bill"),
(tr "subscription.settings.enterprise.unlimited-storage")]
(tr "subscription.settings.enterprise.autosave")]
:cta-text (if subscription (tr "subscription.settings.subscribe") (tr "subscription.settings.try-it-free"))
:cta-link #(open-subscription-modal "enterprise" subscription)
:cta-text-with-icon (tr "subscription.settings.more-information")

View File

@@ -275,10 +275,8 @@
handle-gradient-remove-stop
(mf/use-fn
(mf/deps state)
(fn [index]
(when (> (count (:stops state)) 2)
(st/emit! (dc/remove-gradient-stop index)))))
(st/emit! (dc/remove-gradient-stop index))))
handle-stop-edit-start
(mf/use-fn

View File

@@ -59,6 +59,14 @@
on-unmount children is-selected icon disabled value]}]
(let [submenu-ref (mf/use-ref nil)
hovering? (mf/use-ref false)
on-click'
(mf/use-fn
(mf/deps on-click)
(fn [event]
(st/emit! dw/hide-context-menu)
(when on-click (on-click event))))
on-pointer-enter
(mf/use-fn
(fn []
@@ -96,7 +104,7 @@
:disabled disabled
:data-value value
:ref set-dom-node
:on-click on-click
:on-click on-click'
:on-pointer-enter on-pointer-enter
:on-pointer-leave on-pointer-leave}
[:span
@@ -110,7 +118,7 @@
:disabled disabled
:ref set-dom-node
:data-value value
:on-click on-click
:on-click on-click'
:on-pointer-enter on-pointer-enter
:on-pointer-leave on-pointer-leave}
[:span {:class (stl/css :title)} title]

View File

@@ -41,25 +41,9 @@
""
(ust/format-precision value 2)))
(defn- get-next-font
[{:keys [id] :as current} fonts]
(if (seq fonts)
(let [index (d/index-of-pred fonts #(= (:id %) id))
index (or index -1)
next (ex/ignoring (nth fonts (inc index)))]
(or next (first fonts)))
current))
(defn- get-prev-font
[{:keys [id] :as current} fonts]
(if (seq fonts)
(let [index (d/index-of-pred fonts #(= (:id %) id))
next (ex/ignoring (nth fonts (dec index)))]
(or next (peek fonts)))
current))
(mf/defc font-item*
{::mf/wrap [mf/memo]}
{::mf/wrap [mf/memo]
::mf/private true}
[{:keys [font is-current on-click style]}]
(let [item-ref (mf/use-ref)
on-click (mf/use-fn (mf/deps font) #(on-click font))]
@@ -83,7 +67,7 @@
(declare row-renderer)
(defn filter-fonts
(defn- filter-fonts
[{:keys [term backends]} fonts]
(let [term (str/lower term)
xform (cond-> (map identity)
@@ -96,8 +80,7 @@
(mf/defc font-selector*
[{:keys [on-select on-close current-font show-recent full-size]}]
(let [selected (mf/use-state current-font)
state* (mf/use-state
(let [state* (mf/use-state
#(do {:term "" :backends #{}}))
state (deref state*)
@@ -112,23 +95,41 @@
recent-fonts (mf/with-memo [state recent-fonts]
(filter-fonts state recent-fonts))
full-size? (boolean (and full-size show-recent))
;; Combine recent fonts with filtered fonts, avoiding duplicates
combined-fonts
(mf/with-memo [recent-fonts fonts]
(let [recent-ids (into #{} d/xf:map-id recent-fonts)]
(into recent-fonts (remove #(contains? recent-ids (:id %))) fonts)))
;; Initialize selected with current font index
selected-index
(mf/use-state
(fn []
(or (some (fn [[idx font]]
(when (= (:id current-font) (:id font)) idx))
(map-indexed vector combined-fonts))
0)))
full-size?
(boolean (and full-size show-recent))
select-next
(mf/use-fn
(mf/deps fonts)
(mf/deps combined-fonts)
(fn [event]
(dom/stop-propagation event)
(dom/prevent-default event)
(swap! selected get-next-font fonts)))
(let [next-idx (mod (inc @selected-index) (count combined-fonts))]
(reset! selected-index next-idx))))
select-prev
(mf/use-fn
(mf/deps fonts)
(mf/deps combined-fonts)
(fn [event]
(dom/stop-propagation event)
(dom/prevent-default event)
(swap! selected get-prev-font fonts)))
(let [prev-idx (mod (dec @selected-index) (count combined-fonts))]
(reset! selected-index prev-idx))))
on-select-and-close
(mf/use-fn
@@ -139,35 +140,32 @@
on-key-down
(mf/use-fn
(mf/deps fonts)
(mf/deps combined-fonts)
(fn [event]
(cond
(kbd/up-arrow? event) (select-prev event)
(kbd/down-arrow? event) (select-next event)
(kbd/esc? event) (on-close)
(kbd/enter? event) (do (on-select-and-close @selected))
(kbd/enter? event) (do
(let [selected-font (nth combined-fonts @selected-index)]
(on-select-and-close selected-font)))
:else (dom/focus! (mf/ref-val input)))))
on-filter-change
(mf/use-fn
(fn [event]
(swap! state* assoc :term event)))
on-select-and-close
(mf/use-fn
(mf/deps on-select on-close)
(fn [font]
(on-select font)
(on-close)))]
(swap! state* assoc :term event)
;; Reset selection to first item when filter changes
(reset! selected-index 0)))]
(mf/with-effect [fonts]
(let [key (events/listen js/document "keydown" on-key-down)]
#(events/unlistenByKey key)))
(mf/with-effect [@selected]
(mf/with-effect [@selected-index]
(when-let [inst (mf/ref-val flist)]
(when-let [index (:index @selected)]
(.scrollToRow ^js inst index))))
(when (and (>= @selected-index 0) (< @selected-index (count combined-fonts)))
(.scrollToRow ^js inst @selected-index))))
(mf/with-effect []
(st/emit! (dsc/push-shortcuts :typography {}))
@@ -175,15 +173,12 @@
(st/emit! (dsc/pop-shortcuts :typography))))
(mf/with-effect []
(let [index (d/index-of-pred fonts #(= (:id %) (:id current-font)))
(let [index (d/index-of-pred combined-fonts #(= (:id %) (:id current-font)))
inst (mf/ref-val flist)]
(tm/schedule
#(let [offset (.getOffsetForRow ^js inst #js {:alignment "center" :index index})]
(.scrollToPosition ^js inst offset)))))
(mf/with-effect [(:term state) fonts]
(when (and (seq fonts) (not= (:id @selected) (:id (first fonts))))
(reset! selected (first fonts))))
(when (and index (>= index 0))
(tm/schedule
#(let [offset (.getOffsetForRow ^js inst #js {:alignment "center" :index index})]
(.scrollToPosition ^js inst offset))))))
[:div {:class (stl/css :font-selector)}
[:div {:class (stl/css-case :font-selector-dropdown true :font-selector-dropdown-full-size full-size?)}
@@ -200,7 +195,7 @@
:font font
:style {}
:on-click on-select-and-close
:is-current (= (:id font) (:id @selected))}])])]
:is-current (= idx @selected-index)}])])]
[:div {:class (stl/css-case :fonts-list true
:fonts-list-full-size full-size?)}
@@ -208,17 +203,17 @@
(fn [props]
(let [width (unchecked-get props "width")
height (unchecked-get props "height")
render #(row-renderer fonts @selected on-select-and-close %)]
render #(row-renderer combined-fonts @selected-index on-select-and-close %)]
(mf/html
[:> rvt/List #js {:height height
:ref flist
:width width
:rowCount (count fonts)
:rowCount (count combined-fonts)
:rowHeight 36
:rowRenderer render}])))]]]]))
(defn row-renderer
[fonts selected on-select props]
[fonts selected-index on-select props]
(let [index (unchecked-get props "index")
key (unchecked-get props "key")
style (unchecked-get props "style")
@@ -228,7 +223,7 @@
:font font
:style style
:on-click on-select
:is-current (= (:id font) (:id selected))}])))
:is-current (= index selected-index)}])))
(mf/defc font-options
{::mf/wrap-props false}

View File

@@ -4313,11 +4313,6 @@ msgstr "Please upgrade to match your usage. Contact with the team owner: %s"
msgid "subscription.dashboard.power-up.enterprise-plan"
msgstr "Enterprise plan"
#: src/app/main/ui/dashboard/subscription.cljs:77
#, unused
msgid "subscription.dashboard.power-up.enterprise.description"
msgstr "Advanced security, activity logs, dedicated support and more."
#: src/app/main/ui/dashboard/subscription.cljs:60
#, markdown
msgid "subscription.dashboard.power-up.professional.bottom"
@@ -4357,9 +4352,9 @@ msgstr "Enterprise plan (trial)"
#: src/app/main/ui/dashboard/subscription.cljs:74
#, markdown
msgid "subscription.dashboard.power-up.unlimited.bottom"
msgid "subscription.dashboard.power-up.unlimited.bottom-text"
msgstr ""
"Get extra editors, more storage and backup, advanced security and more. "
"Get extra editors, more backup, unlimited storage and more. "
"[Take a look to the Enterprise plan.|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:70
@@ -4417,9 +4412,8 @@ msgstr "Enterprise (trial)"
msgid "subscription.settings.enterprise.unlimited-storage"
msgstr "Unlimited storage and 90-day autosave versions and file recovery"
#: src/app/main/ui/settings/subscription.cljs:270, src/app/main/ui/settings/subscription.cljs:319
msgid "subscription.settings.enterprise.security"
msgstr "Advanced security"
msgid "subscription.settings.enterprise.autosave"
msgstr "90-day autosave versions and file recovery"
#: src/app/main/ui/settings/subscription.cljs:269, src/app/main/ui/settings/subscription.cljs:318
msgid "subscription.settings.enterprise.capped-bill"

View File

@@ -4340,11 +4340,6 @@ msgstr "Por favor, mejóralo para adaptarlo a tu uso. Contacta con el "
msgid "subscription.dashboard.power-up.enterprise-plan"
msgstr "Plan Enterprise"
#: src/app/main/ui/dashboard/subscription.cljs:77
#, unused
msgid "subscription.dashboard.power-up.enterprise.description"
msgstr "Seguridad avanzada, registros de actividad, asistencia dedicada y mucho más."
#: src/app/main/ui/dashboard/subscription.cljs:60
#, markdown
msgid "subscription.dashboard.power-up.professional.bottom"
@@ -4388,9 +4383,9 @@ msgstr "Plan Unlimited"
#: src/app/main/ui/dashboard/subscription.cljs:74
#, markdown
msgid "subscription.dashboard.power-up.unlimited.bottom"
msgid "subscription.dashboard.power-up.unlimited.bottom-text"
msgstr ""
"Consigue editores adicionales, más almacenamiento y copias de seguridad, seguridad avanzada y mucho más. "
"Consigue editores adicionales, copias de seguridad, almacenamiento ilimitado y mucho más. "
"[Echa un ojo al Plan Enterprise|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:70
@@ -4445,9 +4440,8 @@ msgstr "Enterprise (prueba)"
msgid "subscription.settings.enterprise.unlimited-storage"
msgstr "Almacenamiento ilimitado y versiones de autoguardado de 90 días y recuperación de archivos"
#: src/app/main/ui/settings/subscription.cljs:270, src/app/main/ui/settings/subscription.cljs:319
msgid "subscription.settings.enterprise.security"
msgstr "Seguridad avanzada"
msgid "subscription.settings.enterprise.autosave"
msgstr "Versiones guardadas automáticamente cada 90 días y recuperación de archivos"
#: src/app/main/ui/settings/subscription.cljs:269, src/app/main/ui/settings/subscription.cljs:318
msgid "subscription.settings.enterprise.capped-bill"

View File

@@ -7,7 +7,7 @@ export DEVENV_PNAME="penpotdev";
export CURRENT_USER_ID=$(id -u);
export CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD);
export IMAGEMAGICK_VERSION=7.1.1-47
export IMAGEMAGICK_VERSION=7.1.2-0
# Safe directory to avoid ownership errors with Git
git config --global --add safe.directory /home/penpot/penpot || true