Compare commits

..

19 Commits

Author SHA1 Message Date
Alejandro
3007aa19a2 Merge pull request #6046 from penpot/eva-fix-storybook-icons-list
🐛 Fix storybook icons list scroll
2025-03-11 09:59:42 +01:00
Eva Marco
e20adda766 🐛 Fix storybook icons list scroll 2025-03-11 09:43:35 +01:00
Alejandro
3d9fda7a21 Merge pull request #6025 from penpot/eva-fix-storybook-scroll
🐛 Fix scroll on storybook doc files
2025-03-07 07:52:30 +01:00
Alejandro
7a5dea5cfe Merge pull request #6023 from penpot/marina-consolidate-empty-workspace-board-tool
🎉 Consolidate when workspace empty, board tool selected
2025-03-07 07:49:27 +01:00
alonso.torres
b47df2c230 🐛 Fix problem with components and grid layout 2025-03-06 15:43:55 +01:00
Marina López
b8b3cc641a 🎉 Consolidate when workspace empty, board tool selected 2025-03-06 13:31:12 +01:00
Eva Marco
09ff7372da 🐛 Fix scroll on storybook doc filesç 2025-03-06 12:29:48 +01:00
Alejandro
f45fa95935 Merge pull request #6017 from penpot/alotor-bugfix
🐛 Fix problem with selection colors
2025-03-06 07:35:26 +01:00
alonso.torres
ce02cbc3f1 🐛 Fix problem with selection colors 2025-03-05 14:34:08 +01:00
Alejandro Alonso
b386403fa8 🐛 Fix multiple nav events when open workspace 2025-03-05 12:09:05 +01:00
Alejandro Alonso
0a6e884584 🐛 Remove unnecesary console.log 2025-03-05 12:09:05 +01:00
Alejandro
06f6a49bce Merge pull request #6008 from penpot/superalex-fix-multiple-nav-events-when-open-workspace
🐛 Fix multiple nav events when open workspace
2025-03-05 10:57:51 +01:00
Alejandro Alonso
afd309c62b 🐛 Fix multiple nav events when open workspace 2025-03-05 10:50:47 +01:00
Alejandro Alonso
214a89e20d 📎 Update CHANGES.md file 2025-03-03 07:13:23 +01:00
Yamila Moreno
e64cf9f283 Merge pull request #5908 from penpot/yms-proxy-documentation
📚 Document how to use a proxy
2025-02-28 17:18:46 +01:00
Marina López
3a34c51e43 Add pricing page event 2025-02-28 13:04:15 +01:00
Yamila Moreno
0ff9c44246 🐳 Improve nginx resolvers (#5967) 2025-02-28 09:02:40 +01:00
Yamila Moreno
5bfab454f5 📚 Document how to use a proxy - caddy 2025-02-28 08:43:40 +01:00
Yamila Moreno
5ebde405ea 📚 Document how to use a proxy - nginx 2025-02-28 08:43:40 +01:00
20 changed files with 261 additions and 105 deletions

View File

@@ -1,6 +1,38 @@
# CHANGELOG
## 2.5.0 (Unreleased)
## 2.5.2
### :rocket: Epics and highlights
### :boom: Breaking changes & Deprecations
### :heart: Community contributions (Thank you!)
### :sparkles: New features
- When the workspace is empty, set default the board creation tool [Taiga #9425](https://tree.taiga.io/project/penpot/us/9425)
### :bug: Bugs fixed
- Fix scroll on storybook docs [taiga #9962](https://tree.taiga.io/project/penpot/issue/9962)
- Navigate tracking event firing multiple times [Taiga #10415](https://tree.taiga.io/project/penpot/issue/10415)
- Fix problem with selection colors [Taiga #10376](https://tree.taiga.io/project/penpot/issue/10376)
- Fix scroll on storybook icons list [taiga #9962](https://tree.taiga.io/project/penpot/issue/9962)
## 2.5.1
### :rocket: Epics and highlights
### :boom: Breaking changes & Deprecations
### :heart: Community contributions (Thank you!)
### :sparkles: New features
- Improve Nginx entryponit to get the resolvers dinamically by default
### :bug: Bugs fixed
## 2.5.0
### :rocket: Epics and highlights

View File

@@ -154,7 +154,7 @@
(let [data (::file-data (meta changes))]
(dm/get-in data [:pages-index uuid/zero :objects])))
(defn- apply-changes-local
(defn apply-changes-local
[changes]
(dm/assert!
"expected valid changes"

View File

@@ -747,42 +747,35 @@
(let [omit-touched? (not reset?)
clear-remote-synced? (and initial-root? reset?)
set-remote-synced? (and (not initial-root?) reset?)
changes (cond-> changes
:always
(update-attrs shape-inst
shape-main
root-inst
root-main
container
omit-touched?)
changes
(cond-> changes
:always
(update-attrs shape-inst
shape-main
root-inst
root-main
container
omit-touched?)
(ctl/flex-layout? shape-main)
(update-flex-child-copy-attrs shape-main
shape-inst
library
component
container
omit-touched?)
(ctl/flex-layout? shape-main)
(update-flex-child-copy-attrs shape-main
shape-inst
library
component
container
omit-touched?)
(ctl/grid-layout? shape-main)
(update-grid-copy-attrs shape-main
shape-inst
library
component
container
omit-touched?)
reset?
(change-touched shape-inst
shape-main
container
{:reset-touched? true})
reset?
(change-touched shape-inst
shape-main
container
{:reset-touched? true})
clear-remote-synced?
(change-remote-synced shape-inst container nil)
clear-remote-synced?
(change-remote-synced shape-inst container nil)
set-remote-synced?
(change-remote-synced shape-inst container true))
set-remote-synced?
(change-remote-synced shape-inst container true))
component-container (find-main-container container shape-inst shape-main library component)
@@ -859,23 +852,36 @@
(d/index-of children-inst child-inst)
(d/index-of children-main child-main)
container
omit-touched?))]
omit-touched?))
(compare-children changes
children-inst
children-main
container
component-container
file
libraries
only-inst
only-main
both
swapped
moved
false
reset?
components-v2))))
changes
(compare-children changes
children-inst
children-main
container
component-container
file
libraries
only-inst
only-main
both
swapped
moved
false
reset?
components-v2)
changes
(cond-> changes
(ctl/grid-layout? shape-inst)
(update-grid-copy-attrs
(:id shape-inst)
shape-main
library
component
omit-touched?))]
changes)))
(defn generate-rename-component
"Generate the changes for rename the component with the given id, in the current file library."
@@ -1710,30 +1716,36 @@
(defn- update-grid-copy-attrs
"Synchronizes the `layout-grid-cells` property from the main shape to the copies"
[changes shape-main shape-copy main-container main-component copy-container omit-touched?]
(let [ids-map
(into {}
(comp
(map #(dm/get-in copy-container [:objects %]))
(keep
(fn [copy-shape]
(let [main-shape (ctf/get-ref-shape main-container main-component copy-shape)]
[(:id main-shape) (:id copy-shape)]))))
(:shapes shape-copy))
[changes shape-copy-id shape-main main-container main-component omit-touched?]
(-> changes
(pcb/apply-changes-local)
(pcb/update-shapes
[shape-copy-id]
(fn [shape-copy objects]
(let [ids-map
(into {}
(comp
(map #(get objects %))
(keep
(fn [copy-shape]
(let [main-shape (ctf/get-ref-shape main-container main-component copy-shape)]
[(:id main-shape) (:id copy-shape)]))))
(:shapes shape-copy))
new-changes
(-> (pcb/empty-changes)
(pcb/with-container copy-container)
(pcb/with-objects (:objects copy-container))
(pcb/update-shapes
[(:id shape-copy)]
(fn [shape-copy]
remove-orphan-cells
(fn [cells {:keys [shapes]}]
(let [child? (set shapes)]
(-> cells
(update-vals
(fn [cell]
(update cell :shapes #(filterv child? %)))))))
;; Take cells from main and remap the shapes to assign it to the copy
(let [copy-cells (:layout-grid-cells shape-copy)
main-cells (-> (ctl/remap-grid-cells shape-main ids-map) :layout-grid-cells)]
(assoc shape-copy :layout-grid-cells (ctl/merge-cells copy-cells main-cells omit-touched?))))
{:ignore-touched true}))]
(pcb/concat-changes changes new-changes)))
copy-cells (-> shape-copy :layout-grid-cells (remove-orphan-cells shape-copy))
main-cells (-> shape-main (ctl/remap-grid-cells ids-map) :layout-grid-cells)]
(-> shape-copy
(assoc :layout-grid-cells
(ctl/merge-cells copy-cells main-cells omit-touched?)))))
{:ignore-touched true :with-objects? true})))
(defn- update-grid-main-attrs
"Synchronizes the `layout-grid-cells` property from the copy to the main shape"

View File

@@ -1642,11 +1642,16 @@
"Given target cells update with source cells while trying to keep target as
untouched as possible"
[target-cells source-cells omit-touched?]
(if (not omit-touched?)
source-cells
(if omit-touched?
(letfn [(get-data [cells id]
(dissoc (get cells id) :shapes :row :column :row-span :column-span))]
(dissoc (get cells id) :row :column :row-span :column-span))
(merge-cells [source-cell target-cell]
(-> source-cell
(d/patch-object
(dissoc target-cell :shapes :row :column :row-span :column-span))
(cond-> (d/not-empty? (:shapes target-cell))
(assoc :shapes (:shapes target-cell)))))]
(let [deleted-cells
(into #{}
(filter #(not (contains? source-cells %)))
@@ -1664,5 +1669,6 @@
(reduce
(fn [cells id]
(-> cells
(d/update-when id d/patch-object (get-data target-cells id))))
source-cells))))))
(d/update-when id merge-cells (get target-cells id))))
source-cells))))
source-cells))

View File

@@ -11,6 +11,7 @@ RUN set -ex; \
ADD ./bundle-frontend/ /var/www/app/
ADD ./files/config.js /var/www/app/js/config.js
ADD ./files/nginx.conf /etc/nginx/nginx.conf.template
ADD ./files/resolvers.conf /etc/nginx/overrides.d/resolvers.conf.template
ADD ./files/nginx-mime.types /etc/nginx/mime.types
ADD ./files/nginx-entrypoint.sh /entrypoint.sh

View File

@@ -21,10 +21,14 @@ update_flags /var/www/app/js/config.js
export PENPOT_BACKEND_URI=${PENPOT_BACKEND_URI:-http://penpot-backend:6060};
export PENPOT_EXPORTER_URI=${PENPOT_EXPORTER_URI:-http://penpot-exporter:6061};
export PENPOT_INTERNAL_RESOLVER=${PENPOT_INTERNAL_RESOLVER:-127.0.0.11};
PENPOT_DEFAULT_INTERNAL_RESOLVER="$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf)";
export PENPOT_INTERNAL_RESOLVER=${PENPOT_INTERNAL_RESOLVER:-$PENPOT_DEFAULT_INTERNAL_RESOLVER};
export PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE=${PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE:-367001600}; # Default to 350MiB
envsubst "\$PENPOT_BACKEND_URI,\$PENPOT_EXPORTER_URI,\$PENPOT_INTERNAL_RESOLVER,\$PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE" \
< /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
envsubst "\$PENPOT_BACKEND_URI,\$PENPOT_EXPORTER_URI,\$PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE" \
< /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf;
envsubst "\$PENPOT_INTERNAL_RESOLVER" \
< /etc/nginx/overrides.d/resolvers.conf.template > /etc/nginx/overrides.d/resolvers.conf;
exec "$@";

View File

@@ -46,7 +46,6 @@ http {
proxy_buffer_size 16k;
proxy_busy_buffers_size 24k; # essentially, proxy_buffer_size + 2 small buffers of 4k
proxy_buffers 32 4k;
resolver $PENPOT_INTERNAL_RESOLVER ipv6=off;
map $http_upgrade $connection_upgrade {
default upgrade;

View File

@@ -0,0 +1 @@
resolver $PENPOT_INTERNAL_RESOLVER ipv6=off valid=10s;

View File

@@ -280,6 +280,67 @@ Postgres database and another one for the assets uploaded by your users (images
clips). There may be more volumes if you enable other features, as explained in the file
itself.
### Configure the proxy
Your host configuration needs to make a proxy to http://localhost:9001.
#### Example with NGINX
```bash
server {
listen 80;
server_name penpot.mycompany.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name penpot.mycompany.com;
# This value should be in sync with the corresponding in the docker-compose.yml
# PENPOT_HTTP_SERVER_MAX_BODY_SIZE: 31457280
client_max_body_size 31457280;
# Logs: Configure your logs following the best practices inside your company
access_log /path/to/penpot.access.log;
error_log /path/to/penpot.error.log;
# TLS: Configure your TLS following the best practices inside your company
ssl_certificate /path/to/fullchain;
ssl_certificate_key /path/to/privkey;
# Websockets
location /ws/notifications {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_pass http://localhost:9001/ws/notifications;
}
# Proxy pass
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_pass http://localhost:9001/;
}
}
```
#### Example with CADDY SERVER
```bash
penpot.mycompany.com {
reverse_proxy :9001
tls /path/to/fullchain.pem /path/to/privkey.pem
log {
output file /path/to/penpot.log
}
}
```
### Troubleshooting
Knowing how to do Penpot troubleshooting can be very useful; on the one hand, it helps to create issues easier to resolve, since they include relevant information from the beginning which also makes them get solved faster; on the other hand, many times troubleshooting gives the necessary information to resolve a problem autonomously, without even creating an issue.
@@ -350,7 +411,6 @@ you need.
Therefore, your prerequisite will be to have a Kubernetes cluster on which we can install
Helm.
### What is Helm
*Helm* is the package manager for Kubernetes. A *Chart* is a Helm package. It contains

View File

@@ -70,6 +70,7 @@ export class WorkspacePage extends BaseWebSocketPage {
);
this.toolbarOptions = page.getByTestId("toolbar-options");
this.rectShapeButton = page.getByRole("button", { name: "Rectangle (R)" });
this.moveButton = page.getByRole("button", { name: "Move (V)" });
this.boardButton = page.getByRole("button", { name: "Board (B)" });
this.toggleToolbarButton = page.getByRole("button", {
name: "Toggle toolbar",

View File

@@ -13,6 +13,7 @@ test("Bug 7549 - User clicks on color swatch to display the color picker next to
await workspacePage.setupEmptyFile(page);
await workspacePage.goToWorkspace();
await workspacePage.moveButton.click();
const swatch = workspacePage.page.getByRole("button", { name: "E8E9EA" });
const swatchBox = await swatch.boundingBox();
await swatch.click();
@@ -171,6 +172,7 @@ test("Bug 9900 - Color picker has no inputs for HSV values", async ({
await workspacePage.setupEmptyFile(page);
await workspacePage.goToWorkspace();
await workspacePage.moveButton.click();
const swatch = workspacePage.page.getByRole("button", { name: "E8E9EA" });
await swatch.click();

View File

@@ -178,6 +178,7 @@ test("Bug 10179 - Drag & drop doesn't add colors to the Recent Colors palette",
const workspacePage = new WorkspacePage(page);
await workspacePage.setupEmptyFile();
await workspacePage.goToWorkspace();
await workspacePage.moveButton.click();
await workspacePage.page.keyboard.press("Alt+p");

View File

@@ -0,0 +1,10 @@
// 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 INC
.sb-show-main.sb-main-fullscreen,
.sb-show-main.sb-main-padded {
overflow-y: auto;
}

View File

@@ -13,6 +13,7 @@
@import "common/dependencies/fonts";
@import "common/dependencies/animations";
@import "common/dependencies/highlight.scss";
@import "common/dependencies/storybook.scss";
@import "common/refactor/themes.scss";
@import "common/refactor/design-tokens.scss";

View File

@@ -478,8 +478,7 @@
(rx/of (initialize-page* file-id page-id page)
(dwth/watch-state-changes file-id page-id)
(dwl/watch-component-changes)
(when (cf/external-feature-flag "boards-02" "test")
(select-frame-tool file-id page-id)))
(select-frame-tool file-id page-id))
(rx/of (dcm/go-to-workspace :file-id file-id ::rt/replace true))))))
(defn finalize-page

View File

@@ -62,18 +62,21 @@
;; --- Navigate (Event)
(defn navigated
[match]
[match send-event-info?]
(ptk/reify ::navigated
IDeref
(-deref [_] match)
ev/Event
(-data [_]
(let [route (dm/get-in match [:data :name])
params (get match :path-params)]
(assoc params
::ev/name "navigate"
:route (name route))))
ptk/WatchEvent
(watch [_ _ _]
(when send-event-info?
(let [route (dm/get-in match [:data :name])
params (get match :query-params)]
(rx/of (ptk/event
::ev/event
(assoc params
::ev/name "navigate"
:route (name route)))))))
ptk/UpdateEvent
(update [_ state]
@@ -186,6 +189,21 @@
;; --- History API
;; Check the urls to see if we need to send the navigated event.
;; If two paths are the same we only send the event when there is a
;; change in the parameters `file-id`, `page-id` or `team-id`
(defn- send-event-info?
[old-url new-url]
(let [params [:file-id :page-id :team-id]
new-uri (u/uri new-url)
new-path (:path new-uri)
new-params (-> new-uri :query u/query-string->map (select-keys params))
old-uri (u/uri old-url)
old-path (:path old-uri)
old-params (-> old-uri :query u/query-string->map (select-keys params))]
(or (not= old-path new-path)
(not= new-params old-params))))
(defn initialize-history
[on-change]
(ptk/reify ::initialize-history
@@ -200,11 +218,19 @@
(let [stopper (rx/filter (ptk/type? ::initialize-history) stream)
history (:history state)
router (:router state)]
(ts/schedule #(on-change router (.getToken ^js history)))
(->> (rx/create (fn [subs]
(let [key (e/listen history "navigate" (fn [o] (rx/push! subs (.-token ^js o))))]
(fn []
(bhistory/disable! history)
(e/unlistenByKey key)))))
(ts/schedule #(on-change router (.getToken ^js history) true))
(->> (rx/concat
(rx/of nil nil)
(rx/create
(fn [subs]
(let [key (e/listen history "navigate" (fn [o] (rx/push! subs (.-token ^js o))))]
(fn []
(bhistory/disable! history)
(e/unlistenByKey key))))))
(rx/buffer 2 1)
(rx/take-until stopper)
(rx/subs! #(on-change router %)))))))
(rx/subs!
(fn [[old-url new-url]]
(when (some? new-url)
(let [send? (or (nil? old-url) (send-event-info? old-url new-url))]
(on-change router new-url send?))))))))))

View File

@@ -959,6 +959,7 @@
on-power-up-click
(mf/use-fn
(fn []
(st/emit! (ptk/event ::ev/event {::ev/name "explore-pricing-click" ::ev/origin "dashboard" :section "sidebar"}))
(dom/open-new-window "https://penpot.app/pricing")))]
[:*

View File

@@ -88,7 +88,7 @@
:plugin-url plugin))))
(defn on-navigate
[router path]
[router path send-event-info?]
(let [location (.-location js/document)
[base-path qs] (str/split path "?")
location-path (dm/str (.-origin location) (.-pathname location))
@@ -102,7 +102,7 @@
(st/emit! (rt/assign-exception {:type :not-found}))
(some? match)
(st/emit! (rt/navigated match))
(st/emit! (rt/navigated match send-event-info?))
:else
;; We just recheck with an additional profile request; this

View File

@@ -25,7 +25,7 @@
[rumext.v2 :as mf]))
(mf/defc options*
[{:keys [shape file-id shapes-with-children shared-libs] :as props}]
[{:keys [shape file-id shapes-with-children libraries] :as props}]
(let [shape-id (dm/get-prop shape :id)
shape-type (dm/get-prop shape :type)
@@ -116,7 +116,7 @@
[:> color-selection-menu* {:type shape-type
:shapes shapes-with-children
:file-id file-id
:libraries shared-libs}]
:libraries libraries}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]

View File

@@ -292,7 +292,7 @@
page-id (unchecked-get props "page-id")
file-id (unchecked-get props "file-id")
shared-libs (unchecked-get props "shared-libs")
shared-libs (unchecked-get props "libraries")
show-caps (some #(and (= :path (:type %)) (gsh/open-path? %)) shapes)