From 4f0d3660de8291219e5211c49b20300d50e75490 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 22 Jul 2025 11:51:13 +0200 Subject: [PATCH 1/4] :tada: Add imagemagick docker image build scripts (#6925) * :tada: Add imagemagick docker image build scripts * :paperclip: Add PR feedback changes --- docker/imagemagick/Dockerfile | 91 +++++++++++++++++++++++ docker/images/Dockerfile.backend | 59 ++++++--------- manage.sh | 119 +++++++++++++++++++++---------- 3 files changed, 193 insertions(+), 76 deletions(-) create mode 100644 docker/imagemagick/Dockerfile diff --git a/docker/imagemagick/Dockerfile b/docker/imagemagick/Dockerfile new file mode 100644 index 0000000000..5800979878 --- /dev/null +++ b/docker/imagemagick/Dockerfile @@ -0,0 +1,91 @@ +FROM ubuntu:24.04 +LABEL maintainer="Penpot " + +ENV LANG='C.UTF-8' \ + LC_ALL='C.UTF-8' \ + DEBIAN_FRONTEND=noninteractive \ + TZ=Etc/UTC + +ARG IMAGEMAGICK_VERSION=7.1.1-47 + +RUN set -e; \ + apt-get -qq update; \ + apt-get -qq upgrade; \ + apt-get -qqy --no-install-recommends install \ + autoconf \ + binutils \ + build-essential \ + ca-certificates \ + curl \ + libfftw3-dev \ + libheif-dev \ + libjpeg-dev \ + liblcms2-dev \ + libltdl-dev \ + liblzma-dev \ + libopenexr-dev \ + libpng-dev \ + librsvg2-dev \ + libtiff-dev \ + libtool \ + libwebp-dev \ + libzip-dev \ + libzstd-dev \ + pkg-config \ + ; \ + curl -LfsSo /tmp/magick.tar.gz https://github.com/ImageMagick/ImageMagick/archive/refs/tags/${IMAGEMAGICK_VERSION}.tar.gz; \ + mkdir -p /tmp/magick; \ + cd /tmp/magick; \ + tar -xf /tmp/magick.tar.gz --strip-components=1; \ + ./configure --prefix=/opt/imagick; \ + make -j 2; \ + make install; \ + rm -rf /opt/imagick/lib/libMagick++*; \ + rm -rf /opt/imagick/include; \ + rm -rf /opt/imagick/share; \ + apt-get -qqy --autoremove purge \ + autoconf \ + binutils \ + build-essential \ + ca-certificates \ + curl \ + libfftw3-dev \ + libheif-dev \ + libjpeg-dev \ + liblcms2-dev \ + libltdl-dev \ + liblzma-dev \ + libopenexr-dev \ + libpng-dev \ + librsvg2-dev \ + libtiff-dev \ + libtool\ + libwebp-dev \ + libzip-dev \ + libzstd-dev \ + pkg-config \ + ;\ + apt-get -qqy --no-install-recommends install \ + libfontconfig1 \ + libfreetype6 \ + libglib2.0-0 \ + libgomp1 \ + libheif1 \ + libjpeg-turbo8 \ + liblcms2-2 \ + libopenexr-3-1-30 \ + libopenjp2-7 \ + libpng16-16 \ + librsvg2-2 \ + libtiff6 \ + libwebp7 \ + libwebpdemux2 \ + libwebpmux3 \ + libxml2 \ + libzip4t64 \ + libzstd1 \ + ;\ + apt-get -qqy clean; \ + rm -rf /var/lib/apt/lists/*; + +ENTRYPOINT ["/opt/imagick/bin/magick"] diff --git a/docker/images/Dockerfile.backend b/docker/images/Dockerfile.backend index 045d35a0ae..b8d59818e9 100644 --- a/docker/images/Dockerfile.backend +++ b/docker/images/Dockerfile.backend @@ -6,37 +6,18 @@ ENV LANG='C.UTF-8' \ JAVA_HOME="/opt/jdk" \ DEBIAN_FRONTEND=noninteractive \ NODE_VERSION=v22.16.0 \ - IMAGEMAGICK_VERSION=7.1.1-47 \ TZ=Etc/UTC RUN set -ex; \ apt-get -qq update; \ apt-get -qq upgrade; \ apt-get -qqy --no-install-recommends install \ - curl \ - ca-certificates \ binutils \ - build-essential autoconf libtool pkg-config \ - libltdl-dev \ - libpng-dev libjpeg-dev libtiff-dev libwebp-dev libopenexr-dev libfftw3-dev \ - libzip-dev \ - liblcms2-dev liblzma-dev libzstd-dev \ - libheif-dev librsvg2-dev \ + ca-certificates \ + curl \ ; \ rm -rf /var/lib/apt/lists/* -RUN set -eux; \ - curl -LfsSo /tmp/magick.tar.gz https://github.com/ImageMagick/ImageMagick/archive/refs/tags/${IMAGEMAGICK_VERSION}.tar.gz; \ - mkdir -p /tmp/magick; \ - cd /tmp/magick; \ - tar -xf /tmp/magick.tar.gz --strip-components=1; \ - ./configure --prefix=/opt/imagick; \ - make -j 2; \ - make install; \ - rm -rf /opt/imagick/lib/libMagick++*; \ - rm -rf /opt/imagick/include; \ - rm -rf /opt/imagick/share; - RUN set -eux; \ ARCH="$(dpkg --print-architecture)"; \ case "${ARCH}" in \ @@ -105,33 +86,33 @@ RUN set -ex; \ apt-get -qq update; \ apt-get -qq upgrade; \ apt-get -qqy --no-install-recommends install \ - tzdata \ ca-certificates \ fontconfig \ - woff-tools \ - woff2 \ + fontforge \ python3 \ python3-tabulate \ - fontforge \ + tzdata \ + woff-tools \ + woff2 \ \ - libpng16-16 \ + libfontconfig1 \ + libfreetype6 \ + libglib2.0-0 \ + libgomp1 \ + libheif1 \ libjpeg-turbo8 \ + liblcms2-2 \ + libopenexr-3-1-30 \ + libopenjp2-7 \ + libpng16-16 \ + librsvg2-2 \ libtiff6 \ libwebp7 \ - libopenexr-3-1-30 \ - libfreetype6 \ - libfontconfig1 \ - libglib2.0-0 \ - libxml2 \ - liblcms2-2 \ - libheif1 \ - libopenjp2-7 \ - libzstd1 \ - librsvg2-2 \ - libgomp1 \ - libwebpmux3 \ libwebpdemux2 \ + libwebpmux3 \ + libxml2 \ libzip4t64 \ + libzstd1 \ ; \ find tmp/usr/share/zoneinfo/* -type d ! -name 'Etc' |xargs rm -rf; \ rm -rf /var/lib /var/cache; \ @@ -144,7 +125,7 @@ RUN set -ex; \ COPY --from=build /opt/jre /opt/jre COPY --from=build /opt/node /opt/node -COPY --from=build /opt/imagick /opt/imagick +COPY --from=penpotapp/imagemagick:7.1.1-47 /opt/imagick /opt/imagick COPY --chown=penpot:penpot ./bundle-backend/ /opt/penpot/backend/ USER penpot:penpot diff --git a/manage.sh b/manage.sh index ded023d661..90f69239b9 100755 --- a/manage.sh +++ b/manage.sh @@ -7,6 +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 # Safe directory to avoid ownership errors with Git git config --global --add safe.directory /home/penpot/penpot || true @@ -16,16 +17,23 @@ export JAVA_OPTS=${JAVA_OPTS:-"-Xmx1000m -Xms50m"}; set -e +ARCH=$(uname -m) + +if [[ "$ARCH" == "x86_64" || "$ARCH" == "i386" || "$ARCH" == "i686" ]]; then + ARCH="amd64" +elif [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then + ARCH="arm64" +else + echo "Unknown architecture $ARCH" + exit -1 +fi + + function print-current-version { echo -n "$(git describe --tags --match "*.*.*")"; } -function build-devenv { - set +e; - echo "Building development image $DEVENV_IMGNAME:latest..." - - pushd docker/devenv; - +function setup-buildx { docker run --privileged --rm tonistiigi/binfmt --install all docker buildx inspect penpot > /dev/null 2>&1; @@ -36,19 +44,28 @@ function build-devenv { docker buildx use penpot; docker buildx inspect --bootstrap > /dev/null 2>&1; fi - - # docker build -t $DEVENV_IMGNAME:latest . - docker buildx build --platform linux/amd64,linux/arm64 --push -t $DEVENV_IMGNAME:latest .; - docker pull $DEVENV_IMGNAME:latest; - - popd; } -function build-devenv-local { - echo "Building local only development image $DEVENV_IMGNAME:latest..." +function build-devenv { + set +e; pushd docker/devenv; - docker build -t $DEVENV_IMGNAME:latest .; + + if [ "$1" = "--local" ]; then + echo "Build local only $DEVENV_IMGNAME:latest image"; + docker build -t $DEVENV_IMGNAME:latest .; + else + echo "Build and push $DEVENV_IMGNAME:latest image"; + setup-buildx; + + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --output type=registry \ + -t $DEVENV_IMGNAME:latest .; + + docker pull $DEVENV_IMGNAME:latest; + fi + popd; } @@ -124,6 +141,32 @@ function run-devenv-isolated-shell { $DEVENV_IMGNAME:latest sudo -EH -u penpot bash } +function build-imagemagick-docker-image { + set +e; + echo "Building image penpotapp/imagemagick:$IMAGEMAGICK_VERSION" + + pushd docker/imagemagick; + + output_option="type=registry"; + platform="linux/amd64,linux/arm64"; + + if [ "$1" = "--local" ]; then + output_option="type=docker"; + platform="linux/$ARCH" + fi + + setup-buildx; + + docker buildx build \ + --build-arg IMAGEMAGICK_VERSION=$IMAGEMAGICK_VERSION \ + --platform $platform \ + --output $output_option \ + -t penpotapp/imagemagick:latest \ + -t penpotapp/imagemagick:$IMAGEMAGICK_VERSION .; + + popd; +} + function build { echo ">> build start: $1" local version=$(print-current-version); @@ -219,21 +262,21 @@ function build-docs-bundle { echo ">> bundle docs end"; } -function build-frontend-docker-images { +function build-frontend-docker-image { rsync -avr --delete ./bundles/frontend/ ./docker/images/bundle-frontend/; pushd ./docker/images; docker build -t penpotapp/frontend:$CURRENT_BRANCH -t penpotapp/frontend:latest -f Dockerfile.frontend .; popd; } -function build-backend-docker-images { +function build-backend-docker-image { rsync -avr --delete ./bundles/backend/ ./docker/images/bundle-backend/; pushd ./docker/images; docker build -t penpotapp/backend:$CURRENT_BRANCH -t penpotapp/backend:latest -f Dockerfile.backend .; popd; } -function build-exporter-docker-images { +function build-exporter-docker-image { rsync -avr --delete ./bundles/exporter/ ./docker/images/bundle-exporter/; pushd ./docker/images; docker build -t penpotapp/exporter:$CURRENT_BRANCH -t penpotapp/exporter:latest -f Dockerfile.exporter .; @@ -246,7 +289,7 @@ function usage { echo "Options:" echo "- pull-devenv Pulls docker development oriented image" echo "- build-devenv Build docker development oriented image" - echo "- build-devenv-local Build a local docker development oriented image" + echo "- build-devenv --local Build a local docker development oriented image" echo "- create-devenv Create the development oriented docker compose service." echo "- start-devenv Start the development oriented docker compose service." echo "- stop-devenv Stops the development oriented docker compose service." @@ -263,9 +306,9 @@ function usage { echo "- build-docs-bundle Build docs bundle." echo "" echo "- build-docker-images Build all docker images (frontend, backend and exporter)." - echo "- build-frontend-docker-images Build frontend docker images." - echo "- build-backend-docker-images Build backend docker images." - echo "- build-exporter-docker-images Build exporter docker images." + echo "- build-frontend-docker-image Build frontend docker images." + echo "- build-backend-docker-image Build backend docker images." + echo "- build-exporter-docker-image Build exporter docker images." echo "" echo "- version Show penpot's version." } @@ -281,11 +324,8 @@ case $1 in ;; build-devenv) - build-devenv ${@:2} - ;; - - build-devenv-local) - build-devenv-local ${@:2} + shift; + build-devenv $@; ;; create-devenv) @@ -339,25 +379,30 @@ case $1 in build-docs-bundle; ;; + build-imagemagick-docker-image) + shift; + build-imagemagick-docker-image $@; + ;; + build-docker-images) - build-frontend-docker-images - build-backend-docker-images - build-exporter-docker-images + build-frontend-docker-image + build-backend-docker-image + build-exporter-docker-image ;; - build-frontend-docker-images) - build-frontend-docker-images + build-frontend-docker-image) + build-frontend-docker-image ;; - build-backend-docker-images) - build-backend-docker-images + build-backend-docker-image) + build-backend-docker-image ;; - build-exporter-docker-images) - build-exporter-docker-images + build-exporter-docker-image) + build-exporter-docker-image ;; *) usage ;; -esac \ No newline at end of file +esac From f768ffbdad9f0ff34765465b787310bbc394725f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marina=20L=C3=B3pez?= Date: Tue, 22 Jul 2025 12:31:45 +0200 Subject: [PATCH 2/4] :bug: Fix wrong behaviour for unpaid or canceled subscriptions (#6932) --- .../app/main/ui/dashboard/subscription.cljs | 4 +- .../app/main/ui/settings/subscription.cljs | 62 +++++++++++-------- frontend/translations/en.po | 33 +++++----- frontend/translations/es.po | 33 +++++----- 4 files changed, 67 insertions(+), 65 deletions(-) diff --git a/frontend/src/app/main/ui/dashboard/subscription.cljs b/frontend/src/app/main/ui/dashboard/subscription.cljs index 6f784cda28..e751e27443 100644 --- a/frontend/src/app/main/ui/dashboard/subscription.cljs +++ b/frontend/src/app/main/ui/dashboard/subscription.cljs @@ -61,7 +61,7 @@ [:> cta-power-up* {:top-title (tr "subscription.dashboard.power-up.your-subscription") :top-description (tr "subscription.dashboard.power-up.professional.top-title") - :bottom-description (tr "subscription.dashboard.power-up.professional.bottom-description", subscription-href) + :bottom-description (tr "subscription.dashboard.power-up.professional.bottom", subscription-href) :has-dropdown true}] "unlimited" @@ -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-description", subscription-href) + :bottom-description (tr "subscription.dashboard.power-up.unlimited.bottom", subscription-href) :has-dropdown true}]) "enterprise" diff --git a/frontend/src/app/main/ui/settings/subscription.cljs b/frontend/src/app/main/ui/settings/subscription.cljs index 72bed491a2..2f2819c896 100644 --- a/frontend/src/app/main/ui/settings/subscription.cljs +++ b/frontend/src/app/main/ui/settings/subscription.cljs @@ -62,7 +62,7 @@ (mf/defc subscribe-management-dialog {::mf/register modal/components ::mf/register-as :management-dialog} - [{:keys [subscription-type teams subscribe-to-trial]}] + [{:keys [subscription-type current-subscription teams subscribe-to-trial]}] (let [subscription-name (if subscribe-to-trial (if (= subscription-type "unlimited") @@ -127,12 +127,15 @@ (tr "subscription.settings.management.dialog.no-teams")]) (when (and - (or (= subscription-type "professional") (= subscription-type "unlimited")) + (or (and (= subscription-type "professional") (contains? #{"unlimited" "enterprise"} (:type current-subscription))) + (and (= subscription-type "unlimited") (= (:type current-subscription) "enterprise"))) + (not (contains? #{"unpaid" "canceled"} (:status current-subscription))) (not subscribe-to-trial)) [:div {:class (stl/css :modal-text)} (tr "subscription.settings.management.dialog.downgrade")]) - (if (and (= subscription-type "unlimited") subscribe-to-trial) + (if (and (= subscription-type "unlimited") + (or subscribe-to-trial (contains? #{"unpaid" "canceled"} (:status current-subscription)))) [:& fm/form {:on-submit subscribe-to-unlimited :class (stl/css :seats-form) :form form} @@ -161,7 +164,7 @@ :on-click handle-close-dialog}] [:> fm/submit-button* - {:label (tr "subscription.settings.start-trial") + {:label (if subscribe-to-trial (tr "subscription.settings.start-trial") (tr "labels.continue")) :class (stl/css :primary-button)}]]]] [:div {:class (stl/css :modal-footer)} @@ -232,6 +235,9 @@ (or (= params-subscription "subscribed-to-penpot-unlimited") (= params-subscription "subscribed-to-penpot-enterprise")) + success-modal-is-trial? + (-> route :params :query :trial) + subscription (-> profile :props :subscription) @@ -269,12 +275,13 @@ open-subscription-modal (mf/use-fn (mf/deps teams) - (fn [subscription-type] + (fn [subscription-type current-subscription] (st/emit! (ev/event {::ev/name "open-subscription-modal" ::ev/origin "settings:in-app"})) (st/emit! (modal/show :management-dialog {:subscription-type subscription-type + :current-subscription current-subscription :teams teams :subscribe-to-trial (not subscription)}))))] (mf/with-effect [] @@ -285,7 +292,7 @@ (mf/with-effect [] (dom/set-html-title (tr "subscription.labels"))) - (mf/with-effect [authenticated? show-subscription-success-modal? show-trial-subscription-modal? subscription] + (mf/with-effect [authenticated? show-subscription-success-modal? show-trial-subscription-modal? success-modal-is-trial? subscription] (when ^boolean authenticated? (cond ^boolean show-trial-subscription-modal? @@ -297,6 +304,7 @@ {:subscription-type (if (= params-subscription "subscription-to-penpot-unlimited") "unlimited" "enterprise") + :current-subscription subscription :teams teams :subscribe-to-trial (not subscription)}) (rt/nav :settings-subscription {} {::rt/replace true})) @@ -305,8 +313,12 @@ (st/emit! (modal/show :subscription-success {:subscription-name (if (= params-subscription "subscribed-to-penpot-unlimited") - (tr "subscription.settings.unlimited-trial") - (tr "subscription.settings.enterprise-trial"))}) + (if (= success-modal-is-trial? "true") + (tr "subscription.settings.unlimited-trial") + (tr "subscription.settings.unlimited")) + (if (= success-modal-is-trial? "true") + (tr "subscription.settings.enterprise-trial") + (tr "subscription.settings.enterprise")))}) (du/update-profile-props {:subscription (-> subscription (assoc :type (if (= params-subscription "subscribed-to-penpot-unlimited") @@ -327,7 +339,7 @@ [:> plan-card* {:card-title (tr "subscription.settings.professional") :benefits [(tr "subscription.settings.professional.projects-files"), (tr "subscription.settings.professional.teams-editors"), - (tr "subscription.settings.professional.storage")]}] + (tr "subscription.settings.professional.storage-autosave")]}] "unlimited" (if subscription-is-trial? @@ -336,7 +348,7 @@ :benefits-title (tr "subscription.settings.benefits.all-professional-benefits") :benefits [(tr "subscription.settings.unlimited.teams"), (tr "subscription.settings.unlimited.bill"), - (tr "subscription.settings.unlimited.storage")] + (tr "subscription.settings.unlimited.storage-autosave")] :cta-text (tr "subscription.settings.manage-your-subscription") :cta-link go-to-payments :cta-text-trial (tr "subscription.settings.add-payment-to-continue") @@ -348,7 +360,7 @@ :benefits-title (tr "subscription.settings.benefits.all-unlimited-benefits") :benefits [(tr "subscription.settings.unlimited.teams"), (tr "subscription.settings.unlimited.bill"), - (tr "subscription.settings.unlimited.storage")] + (tr "subscription.settings.unlimited.storage-autosave")] :cta-text (tr "subscription.settings.manage-your-subscription") :cta-link go-to-payments :editors (-> profile :props :subscription :quantity)}]) @@ -358,22 +370,22 @@ [:> 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.support"), - (tr "subscription.settings.enterprise.security"), - (tr "subscription.settings.enterprise.logs")] + :benefits [(tr "subscription.settings.enterprise.security"), + (tr "subscription.settings.enterprise.capped-bill"), + (tr "subscription.settings.enterprise.unlimited-storage")] :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.support"), - (tr "subscription.settings.enterprise.security"), - (tr "subscription.settings.enterprise.logs")] + :benefits [(tr "subscription.settings.enterprise.security"), + (tr "subscription.settings.enterprise.capped-bill"), + (tr "subscription.settings.enterprise.unlimited-storage")] :cta-text (tr "subscription.settings.manage-your-subscription") :cta-link go-to-payments}])) [:div {:class (stl/css :membership-container)} - (when subscribed-since + (when (and subscribed-since (not= subscription-type "professional")) [:div {:class (stl/css :membership)} [:span {:class (stl/css :subscription-member)} i/crown] [:span {:class (stl/css :membership-date)} @@ -392,7 +404,7 @@ :price-period (tr "subscription.settings.price-editor-month") :benefits [(tr "subscription.settings.professional.projects-files"), (tr "subscription.settings.professional.teams-editors"), - (tr "subscription.settings.professional.storage")] + (tr "subscription.settings.professional.storage-autosave")] :cta-text (tr "subscription.settings.subscribe") :cta-link #(open-subscription-modal "professional") :cta-text-with-icon (tr "subscription.settings.more-information") @@ -406,9 +418,9 @@ :benefits-title (tr "subscription.settings.benefits.all-professional-benefits") :benefits [(tr "subscription.settings.unlimited.teams"), (tr "subscription.settings.unlimited.bill"), - (tr "subscription.settings.unlimited.storage")] + (tr "subscription.settings.unlimited.storage-autosave")] :cta-text (if subscription (tr "subscription.settings.subscribe") (tr "subscription.settings.try-it-free")) - :cta-link #(open-subscription-modal "unlimited") + :cta-link #(open-subscription-modal "unlimited" subscription-type) :cta-text-with-icon (tr "subscription.settings.more-information") :cta-link-with-icon go-to-pricing-page}]) @@ -417,10 +429,10 @@ :card-title-icon i/character-e :price-value "$950" :price-period (tr "subscription.settings.price-organization-month") - :benefits-title (tr "subscription.settings.benefits.all-professional-benefits") - :benefits [(tr "subscription.settings.enterprise.support"), - (tr "subscription.settings.enterprise.security"), - (tr "subscription.settings.enterprise.logs")] + :benefits-title (tr "subscription.settings.benefits.all-unlimited-benefits") + :benefits [(tr "subscription.settings.enterprise.security"), + (tr "subscription.settings.enterprise.capped-bill"), + (tr "subscription.settings.enterprise.unlimited-storage")] :cta-text (if subscription (tr "subscription.settings.subscribe") (tr "subscription.settings.try-it-free")) :cta-link #(open-subscription-modal "enterprise") :cta-text-with-icon (tr "subscription.settings.more-information") diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 9da3addd88..fd363eb1f1 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -4320,10 +4320,10 @@ 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-description" +msgid "subscription.dashboard.power-up.professional.bottom" msgstr "" -"Get extra editors and storage, file backup and more with the Unlimited " -"plan[Power up|target:self](%s)" +"Get extra editors and storage, file recovery and more with the Unlimited " +"plan. [Power up|target:self](%s)" #: src/app/main/ui/dashboard/subscription.cljs:59 msgid "subscription.dashboard.power-up.professional.top-title" @@ -4357,10 +4357,10 @@ msgstr "Enterprise plan (trial)" #: src/app/main/ui/dashboard/subscription.cljs:74 #, markdown -msgid "subscription.dashboard.power-up.unlimited.bottom-description" +msgid "subscription.dashboard.power-up.unlimited.bottom" msgstr "" -"Get advanced security, activity logs, dedicated support and more. Take a " -"look to the[Enterprise plan.|target:self](%s)" +"Get extra editors, more storage and backup, advanced security and more. " +"[Take a look to the Enterprise plan.|target:self](%s)" #: src/app/main/ui/dashboard/subscription.cljs:70 #, unused @@ -4414,16 +4414,16 @@ msgid "subscription.settings.enterprise-trial" msgstr "Enterprise (trial)" #: src/app/main/ui/settings/subscription.cljs:271, src/app/main/ui/settings/subscription.cljs:320 -msgid "subscription.settings.enterprise.logs" -msgstr "Activity logs" +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" #: src/app/main/ui/settings/subscription.cljs:269, src/app/main/ui/settings/subscription.cljs:318 -msgid "subscription.settings.enterprise.support" -msgstr "Dedicated support" +msgid "subscription.settings.enterprise.capped-bill" +msgstr "Capped monthly bill" #: src/app/main/ui/dashboard/subscription.cljs:114, src/app/main/ui/settings/subscription.cljs:251, src/app/main/ui/settings/subscription.cljs:262, src/app/main/ui/settings/subscription.cljs:272 msgid "subscription.settings.manage-your-subscription" @@ -4492,8 +4492,8 @@ msgid "subscription.settings.professional.projects-files" msgstr "Unlimited projects, files and drafts" #: src/app/main/ui/settings/subscription.cljs:241, src/app/main/ui/settings/subscription.cljs:292 -msgid "subscription.settings.professional.storage" -msgstr "10GB of storage and 7-day autosave versions" +msgid "subscription.settings.professional.storage-autosave" +msgstr "10GB of storage and 7-day autosave versions and file recovery" #: src/app/main/ui/settings/subscription.cljs:240, src/app/main/ui/settings/subscription.cljs:291 msgid "subscription.settings.professional.teams-editors" @@ -4537,11 +4537,6 @@ msgstr "You've been supporting us with this plan since: %s" msgid "subscription.settings.try-it-free" msgstr "Try it free for 14 days" -#: src/app/main/ui/settings/subscription.cljs:119 -#, unused -msgid "subscription.settings.ulimited.try-it-free" -msgstr "Try it free for 14 days" - #: src/app/main/ui/dashboard/subscription.cljs:108, src/app/main/ui/settings/subscription.cljs:56, src/app/main/ui/settings/subscription.cljs:256, src/app/main/ui/settings/subscription.cljs:299 msgid "subscription.settings.unlimited" msgstr "Unlimited" @@ -4555,8 +4550,8 @@ msgid "subscription.settings.unlimited.bill" msgstr "Capped monthly bill" #: src/app/main/ui/settings/subscription.cljs:250, src/app/main/ui/settings/subscription.cljs:261, src/app/main/ui/settings/subscription.cljs:306 -msgid "subscription.settings.unlimited.storage" -msgstr "25GB of storage and 30-day autosave versions and file backup" +msgid "subscription.settings.unlimited.storage-autosave" +msgstr "25GB of storage and 30-day autosave versions and file recovery" #: src/app/main/ui/settings/subscription.cljs:248, src/app/main/ui/settings/subscription.cljs:259, src/app/main/ui/settings/subscription.cljs:304 msgid "subscription.settings.unlimited.teams" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 06d0bd35c7..f08ce1e96a 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -4347,9 +4347,9 @@ msgstr "Seguridad avanzada, registros de actividad, asistencia dedicada y mucho #: src/app/main/ui/dashboard/subscription.cljs:60 #, markdown -msgid "subscription.dashboard.power-up.professional.bottom-description" +msgid "subscription.dashboard.power-up.professional.bottom" msgstr "" -"Consigue editores y almacenamiento adicionales, copias de seguridad de " +"Consigue editores y almacenamiento adicionales, recuperación de " "archivos y mucho más con el Plan Unlimited[Mejóralo|target:self](%s)" #: src/app/main/ui/dashboard/subscription.cljs:59 @@ -4388,10 +4388,10 @@ msgstr "Plan Unlimited" #: src/app/main/ui/dashboard/subscription.cljs:74 #, markdown -msgid "subscription.dashboard.power-up.unlimited.bottom-description" +msgid "subscription.dashboard.power-up.unlimited.bottom" msgstr "" -"Obtenga seguridad avanzada, registros de actividad, asistencia dedicada y " -"mucho más. Echa un ojo al[Plan Enterprise|target:self](%s)" +"Consigue editores adicionales, más almacenamiento y copias de seguridad, seguridad avanzada y mucho más. " +"[Echa un ojo al Plan Enterprise|target:self](%s)" #: src/app/main/ui/dashboard/subscription.cljs:70 #, unused @@ -4442,16 +4442,16 @@ msgid "subscription.settings.enterprise-trial" msgstr "Enterprise (prueba)" #: src/app/main/ui/settings/subscription.cljs:271, src/app/main/ui/settings/subscription.cljs:320 -msgid "subscription.settings.enterprise.logs" -msgstr "Registros de actividad" +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" #: src/app/main/ui/settings/subscription.cljs:269, src/app/main/ui/settings/subscription.cljs:318 -msgid "subscription.settings.enterprise.support" -msgstr "Apoyo específico" +msgid "subscription.settings.enterprise.capped-bill" +msgstr "Factura mensual limitada" #: src/app/main/ui/dashboard/subscription.cljs:114, src/app/main/ui/settings/subscription.cljs:251, src/app/main/ui/settings/subscription.cljs:262, src/app/main/ui/settings/subscription.cljs:272 msgid "subscription.settings.manage-your-subscription" @@ -4516,8 +4516,8 @@ msgid "subscription.settings.professional.projects-files" msgstr "Proyectos, archivos y borradores ilimitados" #: src/app/main/ui/settings/subscription.cljs:241, src/app/main/ui/settings/subscription.cljs:292 -msgid "subscription.settings.professional.storage" -msgstr "10 GB de almacenamiento y versiones de autoguardado de 7 días" +msgid "subscription.settings.professional.storage-autosave" +msgstr "10 GB de almacenamiento y versiones de autoguardado de 7 días y recuperación de archivos" #: src/app/main/ui/settings/subscription.cljs:240, src/app/main/ui/settings/subscription.cljs:291 msgid "subscription.settings.professional.teams-editors" @@ -4560,11 +4560,6 @@ msgstr "Nos has estado apoyando con este plan desde: %s" msgid "subscription.settings.try-it-free" msgstr "Pruébalo gratis durante 14 días" -#: src/app/main/ui/settings/subscription.cljs:119 -#, unused -msgid "subscription.settings.ulimited.try-it-free" -msgstr "Pruébalo gratis durante 14 días" - #: src/app/main/ui/dashboard/subscription.cljs:108, src/app/main/ui/settings/subscription.cljs:56, src/app/main/ui/settings/subscription.cljs:256, src/app/main/ui/settings/subscription.cljs:299 msgid "subscription.settings.unlimited" msgstr "Unlimited" @@ -4578,10 +4573,10 @@ msgid "subscription.settings.unlimited.bill" msgstr "Factura mensual limitada" #: src/app/main/ui/settings/subscription.cljs:250, src/app/main/ui/settings/subscription.cljs:261, src/app/main/ui/settings/subscription.cljs:306 -msgid "subscription.settings.unlimited.storage" +msgid "subscription.settings.unlimited.storage-autosave" msgstr "" -"25 GB de almacenamiento y 30 días de autoguardado de versiones y copias de " -"seguridad de archivos" +"25 GB de almacenamiento y 30 días de autoguardado de versiones y recuperación " +"de archivos" #: src/app/main/ui/settings/subscription.cljs:248, src/app/main/ui/settings/subscription.cljs:259, src/app/main/ui/settings/subscription.cljs:304 msgid "subscription.settings.unlimited.teams" From ea5521485a78dec991739dcbc094f633d3299b97 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Tue, 22 Jul 2025 12:32:24 +0200 Subject: [PATCH 3/4] :recycle: Remove redundant flag on text overrides (#6933) --- common/src/app/common/logic/libraries.cljc | 123 +++++++++--------- common/src/app/common/types/text.cljc | 19 +-- .../common_tests/logic/text_touched_test.cljc | 2 +- common/test/common_tests/types/text_test.cljc | 2 +- 4 files changed, 72 insertions(+), 74 deletions(-) diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index d928268d6e..3c1479dced 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -1665,27 +1665,62 @@ :shapes all-parents})])))) -(defn- text-partial-change-value - [touched-content untouched-content touched] - (cond - (touched :text-content-structure-same-attrs) - (if (touched :text-content-attribute) - ;; Both structure and attrs has been touched, keep the +(defn- text-change-value + [touched-content ;; The :content of the copy text before updating + untouched-content ;; The :content of the main component + touched] + + (let [main-comps-diff (cttx/get-diff-type touched-content untouched-content) + diff-structure? (contains? main-comps-diff :text-content-structure) + + touched-attrs (cttx/get-first-paragraph-text-attrs touched-content) + ;; Have touched content an uniform style? + thed-unif-style? (cttx/equal-attrs? touched-content touched-attrs) + + untouched-attrs (cttx/get-first-paragraph-text-attrs untouched-content) + ;; Have untouched content an uniform style? + untched-unif-style? (cttx/equal-attrs? untouched-content untouched-attrs)] + (cond + ;; Both text and attrs has been touched, keep the ;; touched-content + (and (touched :text-content-text) (touched :text-content-attribute)) touched-content - ;; Keep the touched-content structure and texts, update - ;; its attrs to make them like the untouched-content - (cttx/copy-attrs-keys touched-content (cttx/get-first-paragraph-text-attrs untouched-content))) - (touched :text-content-text) - ;; Keep the texts touched in touched-content, so copy the - ;; texts from touched-content into untouched-content - (cttx/copy-text-keys touched-content untouched-content) + (touched :text-content-structure) + ;; Special case for adding or removing paragraphs: + ;; If the structure has been touched, but the attrs don't, + ;; and both have uniform attributes, we keep the touched-content structure and + ;; texts, updating its attrs to make them like the untouched-content + (if (and (not (touched :text-content-attribute)) thed-unif-style? untched-unif-style?) + (cttx/copy-attrs-keys touched-content untouched-attrs) + ;; In other case, we keep the touched content + touched-content) + + (touched :text-content-text) + ;; Keep the texts touched in touched-content, so copy the + ;; texts from touched-content into untouched-content + (cttx/copy-text-keys touched-content untouched-content) + + (touched :text-content-attribute) + ;; The untouched content has a different structure, but the touched content had't + ;; touched the structure + (if diff-structure? + ;; If both have uniform attributes, we keep the untouched-content structure and + ;; texts, updating its attrs to make them like the touched-content + (if (and thed-unif-style? untched-unif-style?) + (cttx/copy-attrs-keys untouched-content touched-attrs) + ;; In other case, we keep the touched content + touched-content) + + ;; Keep the attrs touched in touched-content, so copy the + ;; texts from untouched-content into touched-content + (cttx/copy-text-keys untouched-content touched-content)) + + + ;; Nothing is touched + :else + untouched-content))) - (touched :text-content-attribute) - ;; Keep the attrs touched in touched-content, so copy the - ;; texts from untouched-content into touched-content - (cttx/copy-text-keys untouched-content touched-content))) (defn- add-update-attr-operations [attr dest-shape roperations uoperations attr-val] @@ -1700,34 +1735,6 @@ [(conj roperations roperation) (conj uoperations uoperation)])) -(defn- is-text-partial-change? - "Check if the attr update is a text partial change" - [untouched-shape touched-shape] - (let [touched (get touched-shape :touched #{}) - partial-text-keys [:text-content-attribute :text-content-text] - active-keys (filter touched partial-text-keys) - untouched-content (:content untouched-shape) - untouched-attrs (cttx/get-first-paragraph-text-attrs untouched-content) - eq-untouched-attrs? (cttx/equal-attrs? untouched-content untouched-attrs)] - (and - (or - ;; One and only one of the keys is pressent - (= 1 (count active-keys)) - (and - (not (touched :text-content-attribute)) - (touched :text-content-structure-same-attrs))) - - (or - ;; Both has the same structure - (cttx/equal-structure? untouched-content (:content touched-shape)) - - ;; The origin and destiny have different structures, but each have the same attrs - ;; for all the items on its content tree - (and - eq-untouched-attrs? - (touched :text-content-structure-same-attrs)))))) - - (defn- update-attrs "The main function that implements the attribute sync algorithm. Copy attributes that have changed in the origin shape to the dest shape. @@ -1784,13 +1791,13 @@ ;; and attrs (bold, font, etc) are in the same attr :content. ;; If only one of them is touched, we want to adress this case and ;; only update the untouched one - text-partial-change? - (when (and - omit-touched? - (cfh/text-shape? origin-shape) - (= :content attr) - (touched attr-group)) - (is-text-partial-change? origin-shape dest-shape)) + text-content-change? + (and + omit-touched? + (cfh/text-shape? origin-shape) + (= :content attr) + (touched attr-group)) + skip-operations? (or (= (get origin-shape attr) (get dest-shape attr)) @@ -1799,7 +1806,7 @@ ;; When it is a text-partial-change, we should generate operations ;; even when omit-touched? is true, but updating only the text or ;; the attributes, omiting the other part - (not text-partial-change?))) + (not text-content-change?))) attr-val (when-not skip-operations? (cond @@ -1808,10 +1815,10 @@ reset-pos-data? nil - text-partial-change? - (text-partial-change-value (:content dest-shape) - (:content origin-shape) - touched) + text-content-change? + (text-change-value (:content dest-shape) + (:content origin-shape) + touched) :else (get origin-shape attr))) @@ -1824,7 +1831,7 @@ ;; On a text-partial-change, we want to force a position-data reset ;; so it's calculated again [roperations uoperations] - (if (and text-partial-change? (not skip-operations?)) + (if (and text-content-change? (not skip-operations?)) (add-update-attr-operations :position-data dest-shape roperations uoperations nil) [roperations uoperations]) diff --git a/common/src/app/common/types/text.cljc b/common/src/app/common/types/text.cljc index efc1df0bad..04fe4a168d 100644 --- a/common/src/app/common/types/text.cljc +++ b/common/src/app/common/types/text.cljc @@ -83,21 +83,12 @@ compare them, and returns a set with the type of differences. The possibilities are :text-content-text - :text-content-attribute, - :text-content-structure - :text-content-structure-same-attrs." + :text-content-attribute + :text-content-structure" [a b] - (let [diff-type (compare-text-content a b - {:text-cb (fn [acc] (conj acc :text-content-text)) - :attribute-cb (fn [acc _] (conj acc :text-content-attribute))})] - (if-not (contains? diff-type :text-content-structure) - diff-type - (let [;; get attrs of the first paragraph of the first paragraph-set - attrs (get-first-paragraph-text-attrs a)] - (if (and (equal-attrs? a attrs) - (equal-attrs? b attrs)) - #{:text-content-structure :text-content-structure-same-attrs} - diff-type))))) + (compare-text-content a b + {:text-cb (fn [acc] (conj acc :text-content-text)) + :attribute-cb (fn [acc _] (conj acc :text-content-attribute))})) (defn get-diff-attrs "Given two content text structures, conformed by maps and vectors, diff --git a/common/test/common_tests/logic/text_touched_test.cljc b/common/test/common_tests/logic/text_touched_test.cljc index 7aacf4fe52..48ffee1700 100644 --- a/common/test/common_tests/logic/text_touched_test.cljc +++ b/common/test/common_tests/logic/text_touched_test.cljc @@ -103,7 +103,7 @@ file' (thf/apply-changes file changes) copy-child' (ths/get-shape file' :copy-child)] - (t/is (= #{:content-group :text-content-structure :text-content-structure-same-attrs} (:touched copy-child'))))) + (t/is (= #{:content-group :text-content-structure} (:touched copy-child'))))) (t/deftest test-text-copy-changed-structure-diff-attrs (let [;; ==== Setup diff --git a/common/test/common_tests/types/text_test.cljc b/common/test/common_tests/types/text_test.cljc index df1cf4c680..6535cf83ee 100644 --- a/common/test/common_tests/types/text_test.cljc +++ b/common/test/common_tests/types/text_test.cljc @@ -39,7 +39,7 @@ (t/is (= #{:text-content-attribute} diff-attr)) (t/is (= #{:text-content-text :text-content-attribute} diff-both)) (t/is (= #{:text-content-structure} diff-structure)) - (t/is (= #{:text-content-structure :text-content-structure-same-attrs} diff-structure-same-attrs)))) + (t/is (= #{:text-content-structure} diff-structure-same-attrs)))) (t/deftest test-get-diff-attrs From 9d288486d7293893d57a6c9d6894110d1e2248e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Tue, 22 Jul 2025 12:32:42 +0200 Subject: [PATCH 4/4] :bug: Subscription current period dates could be null (#6931) `current-period-start` and `current-period-end` can be null if the invoice has not yet been created in stripe. This happens after the subscription is created, before the webhook is sent. --- backend/src/app/srepl/cli.clj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/src/app/srepl/cli.clj b/backend/src/app/srepl/cli.clj index bb3750e046..e9c441d240 100644 --- a/backend/src/app/srepl/cli.clj +++ b/backend/src/app/srepl/cli.clj @@ -205,9 +205,8 @@ [:trial-start [:maybe ::sm/timestamp]] [:cancel-at [:maybe ::sm/timestamp]] [:canceled-at [:maybe ::sm/timestamp]] - - [:current-period-end ::sm/timestamp] - [:current-period-start ::sm/timestamp] + [:current-period-end [:maybe ::sm/timestamp]] + [:current-period-start [:maybe ::sm/timestamp]] [:cancel-at-period-end :boolean] [:cancellation-details