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

This commit is contained in:
Andrey Antukh
2026-03-17 18:28:39 +01:00
10 changed files with 85 additions and 23 deletions

1
.gitignore vendored
View File

@@ -57,6 +57,7 @@
/frontend/package-lock.json
/frontend/resources/fonts/experiments
/frontend/resources/public/*
/frontend/src/app/render_wasm/api/shared.js
/frontend/storybook-static/
/frontend/target/
/frontend/test-results/

View File

@@ -190,10 +190,14 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn get-points
"Returns points for the given segment, faster version of
the `content->points`."
"Returns points for the given content. Accepts PathData instances or
plain segment vectors. Returns nil for nil content."
[content]
(some-> content segment/get-points))
(when (some? content)
(let [content (if (impl/path-data? content)
content
(impl/path-data content))]
(segment/get-points content))))
(defn calc-selrect
"Calculate selrect from a content. The content can be in a PathData

View File

@@ -52,14 +52,15 @@
[target key & expr]
(if (:ns &env)
(let [target (with-meta target {:tag 'js})]
`(let [~'cache (.-cache ~target)
~'result (.get ~'cache ~key)]
(if ~'result
(do
~'result)
(let [~'result (do ~@expr)]
(.set ~'cache ~key ~'result)
~'result))))
`(let [~'cache (.-cache ~target)]
(if (some? ~'cache)
(let [~'result (.get ~'cache ~key)]
(if ~'result
~'result
(let [~'result (do ~@expr)]
(.set ~'cache ~key ~'result)
~'result)))
(do ~@expr))))
`(do ~@expr)))
(defn- impl-transform-segment

View File

@@ -279,6 +279,12 @@
(t/is (some? points))
(t/is (= 3 (count points))))))
(t/deftest path-get-points-plain-vector-safe
(t/testing "path/get-points does not throw for plain vector content"
(let [points (path/get-points sample-content)]
(t/is (some? points))
(t/is (= 3 (count points))))))
(defn calculate-extremities
"Calculate extremities for the provided content.
A legacy implementation used mainly as reference for testing"

View File

@@ -70,9 +70,11 @@
</main>
<div class="pre-footer">
<a href="https://github.com/penpot/penpot/blob/main/docs/{{ page.inputPath }}">Edit this page on GitHub</a>
&nbsp;or ask a&nbsp;
<a href="https://penpot.app/talk-to-us" target="_blank">question</a>.
<div>Found an issue or want to improve this page?<br><br>
<a href="https://github.com/penpot/penpot/blob/main/docs/{{ page.inputPath }}">Edit this page on GitHub</a>
&nbsp; · &nbsp;
<a href="https://github.com/penpot/penpot/issues/new/choose" target="_blank">Open an issue</a>
</div>
</div>
<footer class="footer">
<div class="footer-inside">

View File

@@ -57,5 +57,5 @@ eleventyNavigation:
<div class="contact-block">
<h2>Contact us</h2>
<p>Need help? <a href="https://penpot.app/talk-to-us" target="_blank">Talk to us</a> or join our <a href="https://community.penpot.app/" target="_blank">community</a>.</p>
<p>Write us at <a href="mailto:support@penpot.app" target="_blank">support@penpot.app</a> or join our <a href="https://community.penpot.app/" target="_blank">Community</a>.</p>
</div>

View File

@@ -187,7 +187,54 @@ python3 manage.py create-profile --skip-tutorial --skip-walkthrough
python3 manage.py create-profile -n "Jane Doe" -e jane@example.com -p secretpassword --skip-tutorial --skip-walkthrough
```
## Team Feature Flags
## Feature Flags
### Frontend flags via config.js
You can enable or disable feature flags on the frontend by creating (or editing) a
`config.js` file at `frontend/resources/public/js/config.js`. This file is
**gitignored**, so it has to be created manually. Your local flags won't affect other developers.
Set the `penpotFlags` variable with a space-separated list of flags:
```js
var penpotFlags = "enable-mcp enable-webhooks enable-access-tokens";
```
Each flag entry uses the format `enable-<flag>` or `disable-<flag>`. They are
merged on top of the built-in defaults, so you only need to list the flags you want
to change.
Some examples of commonly used flags:
- `enable-access-tokens` — enables the Access Tokens section under profile settings.
- `enable-mcp` — enables the MCP server configuration section.
- `enable-webhooks` — enables webhooks configuration.
- `enable-login-with-ldap` — enables LDAP login.
The full list of available flags can be found in `common/src/app/common/flags.cljc`.
After creating or modifying this file, **reload the browser** (no need to restart anything).
### Backend flags via PENPOT_FLAGS
Backend feature flags are controlled through the `PENPOT_FLAGS` environment
variable using the same `enable-<flag>` / `disable-<flag>` format. You can set
this in the `docker/devenv/docker-compose.yaml` file under the `main` service
`environment` section:
```yaml
environment:
- PENPOT_FLAGS=enable-access-tokens enable-mcp
```
This requires **restarting the backend** to take effect.
> **Note**: Some features (e.g., access tokens, webhooks) need both frontend and
> backend flags enabled to work end-to-end. The frontend flag enables the UI, while
> the backend flag enables the corresponding API endpoints.
### Team Feature Flags
To test a Feature Flag, you can enable or disable them by team through the `dbg` page:

View File

@@ -68,7 +68,7 @@
(let [content (st/get-path state :content)
content (if (and (not preserve-move-to)
(= (-> content last :command) :move-to))
(into [] (take (dec (count content)) content))
(path/content (take (dec (count content)) content))
content)]
(st/set-content state content)))

View File

@@ -8,7 +8,7 @@
(:require
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt]
[app.common.types.path.segment :as path.segm]
[app.common.types.path :as path]
[app.main.data.workspace.path.state :as pst]
[app.main.snap :as snap]
[app.main.store :as st]
@@ -167,7 +167,7 @@
ranges-stream
(->> content-stream
(rx/filter some?)
(rx/map path.segm/get-points)
(rx/map path/get-points)
(rx/map snap/create-ranges))]
(->> ms/mouse-position

View File

@@ -214,10 +214,11 @@
(mf/use-effect
deps
(fn []
(let [sub (->> stream (rx/subs! on-subscribe))]
#(do
(rx/dispose! sub)
(when on-dispose (on-dispose))))))))
(when stream
(let [sub (->> stream (rx/subs! on-subscribe))]
#(do
(rx/dispose! sub)
(when on-dispose (on-dispose)))))))))
;; https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
;; FIXME: replace with rumext