mirror of
https://github.com/penpot/penpot.git
synced 2025-07-14 23:27:52 +02:00
Merge branch 'staging'
This commit is contained in:
commit
6e1ce62aad
16 changed files with 202 additions and 118 deletions
|
@ -11,6 +11,7 @@
|
||||||
- Fix weird numeration creating new elements in dashboard [Taiga #4755](https://tree.taiga.io/project/penpot/issue/4755)
|
- Fix weird numeration creating new elements in dashboard [Taiga #4755](https://tree.taiga.io/project/penpot/issue/4755)
|
||||||
- Fix can move shape with lens zoom active [Taiga #4787](https://tree.taiga.io/project/penpot/issue/4787)
|
- Fix can move shape with lens zoom active [Taiga #4787](https://tree.taiga.io/project/penpot/issue/4787)
|
||||||
- Fix social links broken [Taiga #4759](https://tree.taiga.io/project/penpot/issue/4759)
|
- Fix social links broken [Taiga #4759](https://tree.taiga.io/project/penpot/issue/4759)
|
||||||
|
- Fix tooltips on left toolbar [Taiga #4793](https://tree.taiga.io/project/penpot/issue/4793)
|
||||||
|
|
||||||
## 1.17.0
|
## 1.17.0
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ cp ../CHANGES.md target/classes/changelog.md;
|
||||||
|
|
||||||
clojure -T:build jar;
|
clojure -T:build jar;
|
||||||
mv target/penpot.jar target/dist/penpot.jar
|
mv target/penpot.jar target/dist/penpot.jar
|
||||||
|
cp resources/log4j2.xml target/dist/log4j2.xml
|
||||||
cp scripts/run.template.sh target/dist/run.sh;
|
cp scripts/run.template.sh target/dist/run.sh;
|
||||||
cp scripts/manage.py target/dist/manage.py
|
cp scripts/manage.py target/dist/manage.py
|
||||||
chmod +x target/dist/run.sh;
|
chmod +x target/dist/run.sh;
|
||||||
|
|
|
@ -18,5 +18,7 @@ if [ -f ./environ ]; then
|
||||||
source ./environ
|
source ./environ
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
export JVM_OPTS="-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager -Dlog4j2.configurationFile=log4j2.xml -XX:-OmitStackTraceInFastThrow $JVM_OPTS"
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
exec $JAVA_CMD $JVM_OPTS "$@" -jar penpot.jar -m app.main
|
exec $JAVA_CMD $JVM_OPTS "$@" -jar penpot.jar -m app.main
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defn- discover-oidc-config
|
(defn- discover-oidc-config
|
||||||
[cfg {:keys [::base-uri] :as opts}]
|
[cfg {:keys [base-uri] :as opts}]
|
||||||
(let [discovery-uri (u/join base-uri ".well-known/openid-configuration")
|
(let [discovery-uri (u/join base-uri ".well-known/openid-configuration")
|
||||||
response (ex/try! (http/req! cfg
|
response (ex/try! (http/req! cfg
|
||||||
{:method :get :uri (str discovery-uri)}
|
{:method :get :uri (str discovery-uri)}
|
||||||
|
@ -64,10 +64,17 @@
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
(= 200 (:status response))
|
(= 200 (:status response))
|
||||||
(let [data (json/decode (:body response))]
|
(let [data (json/decode (:body response))
|
||||||
{:token-uri (get data :token_endpoint)
|
token-uri (get data :token_endpoint)
|
||||||
:auth-uri (get data :authorization_endpoint)
|
auth-uri (get data :authorization_endpoint)
|
||||||
:user-uri (get data :userinfo_endpoint)})
|
user-uri (get data :userinfo_endpoint)]
|
||||||
|
(l/debug :hint "oidc uris discovered"
|
||||||
|
:token-uri token-uri
|
||||||
|
:auth-uri auth-uri
|
||||||
|
:user-uri user-uri)
|
||||||
|
{:token-uri token-uri
|
||||||
|
:auth-uri auth-uri
|
||||||
|
:user-uri user-uri})
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(do
|
(do
|
||||||
|
@ -110,7 +117,7 @@
|
||||||
(if-let [opts (prepare-oidc-opts cfg)]
|
(if-let [opts (prepare-oidc-opts cfg)]
|
||||||
(do
|
(do
|
||||||
(l/info :hint "provider initialized"
|
(l/info :hint "provider initialized"
|
||||||
:provider :oidc
|
:provider "oidc"
|
||||||
:method (if (:discover? opts) "discover" "manual")
|
:method (if (:discover? opts) "discover" "manual")
|
||||||
:client-id (:client-id opts)
|
:client-id (:client-id opts)
|
||||||
:client-secret (obfuscate-string (:client-secret opts))
|
:client-secret (obfuscate-string (:client-secret opts))
|
||||||
|
@ -122,7 +129,7 @@
|
||||||
:roles (:roles opts))
|
:roles (:roles opts))
|
||||||
opts)
|
opts)
|
||||||
(do
|
(do
|
||||||
(l/warn :hint "unable to initialize auth provider, missing configuration" :provider :oidc)
|
(l/warn :hint "unable to initialize auth provider, missing configuration" :provider "oidc")
|
||||||
nil))))
|
nil))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -144,13 +151,13 @@
|
||||||
(string? (:client-secret opts)))
|
(string? (:client-secret opts)))
|
||||||
(do
|
(do
|
||||||
(l/info :hint "provider initialized"
|
(l/info :hint "provider initialized"
|
||||||
:provider :google
|
:provider "google"
|
||||||
:client-id (:client-id opts)
|
:client-id (:client-id opts)
|
||||||
:client-secret (obfuscate-string (:client-secret opts)))
|
:client-secret (obfuscate-string (:client-secret opts)))
|
||||||
opts)
|
opts)
|
||||||
|
|
||||||
(do
|
(do
|
||||||
(l/warn :hint "unable to initialize auth provider, missing configuration" :provider :google)
|
(l/warn :hint "unable to initialize auth provider, missing configuration" :provider "google")
|
||||||
nil)))))
|
nil)))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -196,13 +203,13 @@
|
||||||
(string? (:client-secret opts)))
|
(string? (:client-secret opts)))
|
||||||
(do
|
(do
|
||||||
(l/info :hint "provider initialized"
|
(l/info :hint "provider initialized"
|
||||||
:provider :github
|
:provider "github"
|
||||||
:client-id (:client-id opts)
|
:client-id (:client-id opts)
|
||||||
:client-secret (obfuscate-string (:client-secret opts)))
|
:client-secret (obfuscate-string (:client-secret opts)))
|
||||||
opts)
|
opts)
|
||||||
|
|
||||||
(do
|
(do
|
||||||
(l/warn :hint "unable to initialize auth provider, missing configuration" :provider :github)
|
(l/warn :hint "unable to initialize auth provider, missing configuration" :provider "github")
|
||||||
nil)))))
|
nil)))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -225,14 +232,14 @@
|
||||||
(string? (:client-secret opts)))
|
(string? (:client-secret opts)))
|
||||||
(do
|
(do
|
||||||
(l/info :hint "provider initialized"
|
(l/info :hint "provider initialized"
|
||||||
:provider :gitlab
|
:provider "gitlab"
|
||||||
:base-uri base
|
:base-uri base
|
||||||
:client-id (:client-id opts)
|
:client-id (:client-id opts)
|
||||||
:client-secret (obfuscate-string (:client-secret opts)))
|
:client-secret (obfuscate-string (:client-secret opts)))
|
||||||
opts)
|
opts)
|
||||||
|
|
||||||
(do
|
(do
|
||||||
(l/warn :hint "unable to initialize auth provider, missing configuration" :provider :gitlab)
|
(l/warn :hint "unable to initialize auth provider, missing configuration" :provider "gitlab")
|
||||||
nil)))))
|
nil)))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -275,8 +282,19 @@
|
||||||
"accept" "application/json"}
|
"accept" "application/json"}
|
||||||
:uri (:token-uri provider)
|
:uri (:token-uri provider)
|
||||||
:body (u/map->query-string params)}]
|
:body (u/map->query-string params)}]
|
||||||
|
|
||||||
|
(l/trace :hint "request access token"
|
||||||
|
:provider (:name provider)
|
||||||
|
:client-id (:client-id provider)
|
||||||
|
:client-secret (obfuscate-string (:client-secret provider))
|
||||||
|
:grant-type (:grant_type params)
|
||||||
|
:redirect-uri (:redirect_uri params))
|
||||||
|
|
||||||
(->> (http/req! cfg req)
|
(->> (http/req! cfg req)
|
||||||
(p/map (fn [{:keys [status body] :as res}]
|
(p/map (fn [{:keys [status body] :as res}]
|
||||||
|
(l/trace :hint "access token response"
|
||||||
|
:status status
|
||||||
|
:body body)
|
||||||
(if (= status 200)
|
(if (= status 200)
|
||||||
(let [data (json/decode body)]
|
(let [data (json/decode body)]
|
||||||
{:token (get data :access_token)
|
{:token (get data :access_token)
|
||||||
|
@ -289,12 +307,19 @@
|
||||||
(defn- retrieve-user-info
|
(defn- retrieve-user-info
|
||||||
[{:keys [provider] :as cfg} tdata]
|
[{:keys [provider] :as cfg} tdata]
|
||||||
(letfn [(retrieve []
|
(letfn [(retrieve []
|
||||||
|
(l/trace :hint "request user info"
|
||||||
|
:uri (:user-uri provider)
|
||||||
|
:token (obfuscate-string (:token tdata))
|
||||||
|
:token-type (:type tdata))
|
||||||
(http/req! cfg
|
(http/req! cfg
|
||||||
{:uri (:user-uri provider)
|
{:uri (:user-uri provider)
|
||||||
:headers {"Authorization" (str (:type tdata) " " (:token tdata))}
|
:headers {"Authorization" (str (:type tdata) " " (:token tdata))}
|
||||||
:timeout 6000
|
:timeout 6000
|
||||||
:method :get}))
|
:method :get}))
|
||||||
(validate-response [response]
|
(validate-response [response]
|
||||||
|
(l/trace :hint "user info response"
|
||||||
|
:status (:status response)
|
||||||
|
:body (:body response))
|
||||||
(when-not (s/int-in-range? 200 300 (:status response))
|
(when-not (s/int-in-range? 200 300 (:status response))
|
||||||
(ex/raise :type :internal
|
(ex/raise :type :internal
|
||||||
:code :unable-to-retrieve-user-info
|
:code :unable-to-retrieve-user-info
|
||||||
|
@ -309,7 +334,7 @@
|
||||||
(if-let [get-email-fn (:get-email-fn provider)]
|
(if-let [get-email-fn (:get-email-fn provider)]
|
||||||
(get-email-fn tdata info)
|
(get-email-fn tdata info)
|
||||||
(let [attr-kw (cf/get :oidc-email-attr :email)]
|
(let [attr-kw (cf/get :oidc-email-attr :email)]
|
||||||
(get info attr-kw))))
|
(p/resolved (get info attr-kw)))))
|
||||||
|
|
||||||
(get-name [info]
|
(get-name [info]
|
||||||
(let [attr-kw (cf/get :oidc-name-attr :name)]
|
(let [attr-kw (cf/get :oidc-name-attr :name)]
|
||||||
|
@ -325,6 +350,7 @@
|
||||||
(qualify-props provider))}))
|
(qualify-props provider))}))
|
||||||
|
|
||||||
(validate-info [info]
|
(validate-info [info]
|
||||||
|
(l/trace :hint "authentication info" :info info)
|
||||||
(when-not (s/valid? ::info info)
|
(when-not (s/valid? ::info info)
|
||||||
(l/warn :hint "received incomplete profile info object (please set correct scopes)"
|
(l/warn :hint "received incomplete profile info object (please set correct scopes)"
|
||||||
:info (pr-str info))
|
:info (pr-str info))
|
||||||
|
@ -334,10 +360,10 @@
|
||||||
:info info))
|
:info info))
|
||||||
info)]
|
info)]
|
||||||
|
|
||||||
(-> (retrieve)
|
(->> (retrieve)
|
||||||
(p/then validate-response)
|
(p/fmap validate-response)
|
||||||
(p/then process-response)
|
(p/mcat process-response)
|
||||||
(p/then validate-info))))
|
(p/fmap validate-info))))
|
||||||
|
|
||||||
(s/def ::backend ::us/not-empty-string)
|
(s/def ::backend ::us/not-empty-string)
|
||||||
(s/def ::email ::us/not-empty-string)
|
(s/def ::email ::us/not-empty-string)
|
||||||
|
|
|
@ -64,8 +64,11 @@
|
||||||
min-width (max min-width 0.01)
|
min-width (max min-width 0.01)
|
||||||
min-height (max min-height 0.01)]
|
min-height (max min-height 0.01)]
|
||||||
|
|
||||||
(cond-> [base-p]
|
(cond-> [base-p
|
||||||
(or col? h-start?)
|
(gpt/add base-p (hv 0.01))
|
||||||
|
(gpt/add base-p (vv 0.01))]
|
||||||
|
|
||||||
|
(and col? h-start?)
|
||||||
(conj (gpt/add base-p (hv min-width)))
|
(conj (gpt/add base-p (hv min-width)))
|
||||||
|
|
||||||
(and col? h-center?)
|
(and col? h-center?)
|
||||||
|
@ -74,7 +77,7 @@
|
||||||
(and col? h-center?)
|
(and col? h-center?)
|
||||||
(conj (gpt/subtract base-p (hv min-width)))
|
(conj (gpt/subtract base-p (hv min-width)))
|
||||||
|
|
||||||
(or row? v-start?)
|
(and row? v-start?)
|
||||||
(conj (gpt/add base-p (vv min-height)))
|
(conj (gpt/add base-p (vv min-height)))
|
||||||
|
|
||||||
(and row? v-center?)
|
(and row? v-center?)
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
(ns app.common.geom.shapes.points
|
(ns app.common.geom.shapes.points
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes.common :as gco]
|
[app.common.geom.shapes.common :as gco]
|
||||||
[app.common.geom.shapes.intersect :as gsi]
|
[app.common.geom.shapes.intersect :as gsi]
|
||||||
|
@ -115,7 +116,9 @@
|
||||||
(max tv-max ctv)]))
|
(max tv-max ctv)]))
|
||||||
|
|
||||||
[th-min th-max tv-min tv-max]
|
[th-min th-max tv-min tv-max]
|
||||||
(->> child-bounds (reduce find-boundary-ts [##Inf ##-Inf ##Inf ##-Inf]))
|
(->> child-bounds
|
||||||
|
(filter #(and (d/num? (:x %)) (d/num? (:y %))))
|
||||||
|
(reduce find-boundary-ts [##Inf ##-Inf ##Inf ##-Inf]))
|
||||||
|
|
||||||
minv-start (pv tv-min)
|
minv-start (pv tv-min)
|
||||||
minv-end (gpt/add minv-start hv)
|
minv-end (gpt/add minv-start hv)
|
||||||
|
|
|
@ -134,25 +134,41 @@
|
||||||
(defn wrap? [{:keys [layout-wrap-type]}]
|
(defn wrap? [{:keys [layout-wrap-type]}]
|
||||||
(= layout-wrap-type :wrap))
|
(= layout-wrap-type :wrap))
|
||||||
|
|
||||||
(defn fill-width? [child]
|
(defn fill-width?
|
||||||
(= :fill (:layout-item-h-sizing child)))
|
([objects id]
|
||||||
|
(= :fill (dm/get-in objects [id :layout-item-h-sizing])))
|
||||||
|
([child]
|
||||||
|
(= :fill (:layout-item-h-sizing child))))
|
||||||
|
|
||||||
(defn fill-height? [child]
|
(defn fill-height?
|
||||||
(= :fill (:layout-item-v-sizing child)))
|
([objects id]
|
||||||
|
(= :fill (dm/get-in objects [id :layout-item-v-sizing])))
|
||||||
|
([child]
|
||||||
|
(= :fill (:layout-item-v-sizing child))))
|
||||||
|
|
||||||
(defn auto-width? [child]
|
(defn auto-width?
|
||||||
(= :auto (:layout-item-h-sizing child)))
|
([objects id]
|
||||||
|
(= :auto (dm/get-in objects [id :layout-item-h-sizing])))
|
||||||
|
([child]
|
||||||
|
(= :auto (:layout-item-h-sizing child))))
|
||||||
|
|
||||||
(defn auto-height? [child]
|
(defn auto-height?
|
||||||
(= :auto (:layout-item-v-sizing child)))
|
([objects id]
|
||||||
|
(= :auto (dm/get-in objects [id :layout-item-v-sizing])))
|
||||||
|
([child]
|
||||||
|
(= :auto (:layout-item-v-sizing child))))
|
||||||
|
|
||||||
(defn col?
|
(defn col?
|
||||||
[{:keys [layout-flex-dir]}]
|
([objects id]
|
||||||
(or (= :column layout-flex-dir) (= :column-reverse layout-flex-dir)))
|
(col? (get objects id)))
|
||||||
|
([{:keys [layout-flex-dir]}]
|
||||||
|
(or (= :column layout-flex-dir) (= :column-reverse layout-flex-dir))))
|
||||||
|
|
||||||
(defn row?
|
(defn row?
|
||||||
[{:keys [layout-flex-dir]}]
|
([objects id]
|
||||||
(or (= :row layout-flex-dir) (= :row-reverse layout-flex-dir)))
|
(row? (get objects id)))
|
||||||
|
([{:keys [layout-flex-dir]}]
|
||||||
|
(or (= :row layout-flex-dir) (= :row-reverse layout-flex-dir))))
|
||||||
|
|
||||||
(defn gaps
|
(defn gaps
|
||||||
[{:keys [layout-gap]}]
|
[{:keys [layout-gap]}]
|
||||||
|
@ -315,3 +331,22 @@
|
||||||
|
|
||||||
(defn align-self-stretch? [{:keys [layout-item-align-self]}]
|
(defn align-self-stretch? [{:keys [layout-item-align-self]}]
|
||||||
(= :stretch layout-item-align-self))
|
(= :stretch layout-item-align-self))
|
||||||
|
|
||||||
|
(defn change-h-sizing?
|
||||||
|
[frame-id objects children-ids]
|
||||||
|
(and (layout? objects frame-id)
|
||||||
|
(auto-width? objects frame-id)
|
||||||
|
(or (and (col? objects frame-id)
|
||||||
|
(every? (partial fill-width? objects) children-ids))
|
||||||
|
(and (row? objects frame-id)
|
||||||
|
(some (partial fill-width? objects) children-ids)))))
|
||||||
|
|
||||||
|
(defn change-v-sizing?
|
||||||
|
[frame-id objects children-ids]
|
||||||
|
(and (layout? objects frame-id)
|
||||||
|
(auto-height? objects frame-id)
|
||||||
|
(or (and (col? objects frame-id)
|
||||||
|
(some (partial fill-height? objects) children-ids))
|
||||||
|
(and (row? objects frame-id)
|
||||||
|
(every? (partial fill-height? objects) children-ids)))))
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ volumes:
|
||||||
postgres_data_pg15:
|
postgres_data_pg15:
|
||||||
user_data:
|
user_data:
|
||||||
minio_data:
|
minio_data:
|
||||||
|
redis_data:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
main:
|
main:
|
||||||
|
@ -80,22 +81,6 @@ services:
|
||||||
- 9000:9000
|
- 9000:9000
|
||||||
- 9001:9001
|
- 9001:9001
|
||||||
|
|
||||||
# keycloak:
|
|
||||||
# image: "quay.io/keycloak/keycloak:15.0.2"
|
|
||||||
# environment:
|
|
||||||
# - DB_VENDOR=POSTGRES
|
|
||||||
# - DB_ADDR=postgres
|
|
||||||
# - DB_DATABASE=keycloak
|
|
||||||
# - DB_USER=keycloak
|
|
||||||
# - DB_SCHEMA=public
|
|
||||||
# - DB_PASSWORD=keycloak
|
|
||||||
# - KEYCLOAK_USER=admin
|
|
||||||
# - KEYCLOAK_PASSWORD=admin
|
|
||||||
# expose:
|
|
||||||
# - '8080'
|
|
||||||
# ports:
|
|
||||||
# - "8080:8080"
|
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:15
|
image: postgres:15
|
||||||
command: postgres -c config_file=/etc/postgresql.conf
|
command: postgres -c config_file=/etc/postgresql.conf
|
||||||
|
@ -116,6 +101,8 @@ services:
|
||||||
hostname: "penpot-devenv-redis"
|
hostname: "penpot-devenv-redis"
|
||||||
container_name: "penpot-devenv-redis"
|
container_name: "penpot-devenv-redis"
|
||||||
restart: always
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- "redis_data:/data"
|
||||||
|
|
||||||
mailer:
|
mailer:
|
||||||
image: sj26/mailcatcher:latest
|
image: sj26/mailcatcher:latest
|
||||||
|
|
|
@ -13,6 +13,7 @@ RUN set -ex; \
|
||||||
apt-get -qq update; \
|
apt-get -qq update; \
|
||||||
apt-get -qq upgrade; \
|
apt-get -qq upgrade; \
|
||||||
apt-get -qqy --no-install-recommends install \
|
apt-get -qqy --no-install-recommends install \
|
||||||
|
nano \
|
||||||
curl \
|
curl \
|
||||||
tzdata \
|
tzdata \
|
||||||
locales \
|
locales \
|
||||||
|
|
|
@ -37,7 +37,7 @@ $height-palette-max: 80px;
|
||||||
.left-toolbar {
|
.left-toolbar {
|
||||||
grid-area: toolbar;
|
grid-area: toolbar;
|
||||||
width: $width-left-toolbar;
|
width: $width-left-toolbar;
|
||||||
overflow-y: scroll;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -651,20 +651,20 @@
|
||||||
(-> (pcb/empty-changes it page-id)
|
(-> (pcb/empty-changes it page-id)
|
||||||
(pcb/with-objects objects)
|
(pcb/with-objects objects)
|
||||||
|
|
||||||
; Move the shapes
|
;; Move the shapes
|
||||||
(pcb/change-parent parent-id
|
(pcb/change-parent parent-id
|
||||||
shapes
|
shapes
|
||||||
to-index)
|
to-index)
|
||||||
|
|
||||||
; Remove empty groups
|
;; Remove empty groups
|
||||||
(pcb/remove-objects groups-to-delete)
|
(pcb/remove-objects groups-to-delete)
|
||||||
|
|
||||||
; Unmask groups whose mask have moved outside
|
;; Unmask groups whose mask have moved outside
|
||||||
(pcb/update-shapes groups-to-unmask
|
(pcb/update-shapes groups-to-unmask
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc shape :masked-group? false)))
|
(assoc shape :masked-group? false)))
|
||||||
|
|
||||||
; Detach shapes moved out of their component
|
;; Detach shapes moved out of their component
|
||||||
(pcb/update-shapes shapes-to-detach
|
(pcb/update-shapes shapes-to-detach
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc shape :component-id nil
|
(assoc shape :component-id nil
|
||||||
|
@ -674,17 +674,17 @@
|
||||||
:shape-ref nil
|
:shape-ref nil
|
||||||
:touched nil)))
|
:touched nil)))
|
||||||
|
|
||||||
; Make non root a component moved inside another one
|
;; Make non root a component moved inside another one
|
||||||
(pcb/update-shapes shapes-to-deroot
|
(pcb/update-shapes shapes-to-deroot
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc shape :component-root? nil)))
|
(assoc shape :component-root? nil)))
|
||||||
|
|
||||||
; Make root a subcomponent moved outside its parent component
|
;; Make root a subcomponent moved outside its parent component
|
||||||
(pcb/update-shapes shapes-to-reroot
|
(pcb/update-shapes shapes-to-reroot
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc shape :component-root? true)))
|
(assoc shape :component-root? true)))
|
||||||
|
|
||||||
; Reset constraints depending on the new parent
|
;; Reset constraints depending on the new parent
|
||||||
(pcb/update-shapes shapes-to-unconstraint
|
(pcb/update-shapes shapes-to-unconstraint
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(let [parent (get objects parent-id)
|
(let [parent (get objects parent-id)
|
||||||
|
@ -699,7 +699,19 @@
|
||||||
:constraints-v (gsh/default-constraints-v moved-shape))))
|
:constraints-v (gsh/default-constraints-v moved-shape))))
|
||||||
{:ignore-touched true})
|
{:ignore-touched true})
|
||||||
|
|
||||||
; Resize parent containers that need to
|
;; Fix the sizing when moving a shape
|
||||||
|
(pcb/update-shapes parents
|
||||||
|
(fn [parent]
|
||||||
|
(if (ctl/layout? parent)
|
||||||
|
(cond-> parent
|
||||||
|
(ctl/change-h-sizing? (:id parent) objects (:shapes parent))
|
||||||
|
(assoc :layout-item-h-sizing :fix)
|
||||||
|
|
||||||
|
(ctl/change-v-sizing? (:id parent) objects (:shapes parent))
|
||||||
|
(assoc :layout-item-v-sizing :fix))
|
||||||
|
parent)))
|
||||||
|
|
||||||
|
;; Resize parent containers that need to
|
||||||
(pcb/resize-parents parents))))
|
(pcb/resize-parents parents))))
|
||||||
|
|
||||||
(defn relocate-shapes
|
(defn relocate-shapes
|
||||||
|
@ -719,9 +731,9 @@
|
||||||
|
|
||||||
;; If we try to move a parent into a child we remove it
|
;; If we try to move a parent into a child we remove it
|
||||||
ids (filter #(not (cph/is-parent? objects parent-id %)) ids)
|
ids (filter #(not (cph/is-parent? objects parent-id %)) ids)
|
||||||
parents (if ignore-parents?
|
|
||||||
#{parent-id}
|
all-parents (into #{parent-id} (map #(cph/get-parent-id objects %)) ids)
|
||||||
(into #{parent-id} (map #(cph/get-parent-id objects %)) ids))
|
parents (if ignore-parents? #{parent-id} all-parents)
|
||||||
|
|
||||||
groups-to-delete
|
groups-to-delete
|
||||||
(loop [current-id (first parents)
|
(loop [current-id (first parents)
|
||||||
|
@ -814,17 +826,12 @@
|
||||||
shapes-to-reroot
|
shapes-to-reroot
|
||||||
shapes-to-deroot
|
shapes-to-deroot
|
||||||
ids)
|
ids)
|
||||||
|
|
||||||
layouts-to-update
|
|
||||||
(into #{}
|
|
||||||
(filter (partial ctl/layout? objects))
|
|
||||||
(concat [parent-id] (cph/get-parent-ids objects parent-id)))
|
|
||||||
undo-id (js/Symbol)]
|
undo-id (js/Symbol)]
|
||||||
|
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/commit-changes changes)
|
(dch/commit-changes changes)
|
||||||
(dwco/expand-collapse parent-id)
|
(dwco/expand-collapse parent-id)
|
||||||
(ptk/data-event :layout/update layouts-to-update)
|
(ptk/data-event :layout/update (concat all-parents ids))
|
||||||
(dwu/commit-undo-transaction undo-id))))))
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
(defn relocate-selected-shapes
|
(defn relocate-selected-shapes
|
||||||
|
|
|
@ -174,42 +174,62 @@
|
||||||
modif-tree)))
|
modif-tree)))
|
||||||
|
|
||||||
(defn build-change-frame-modifiers
|
(defn build-change-frame-modifiers
|
||||||
[modif-tree objects selected target-frame drop-index]
|
[modif-tree objects selected target-frame-id drop-index]
|
||||||
|
|
||||||
(let [origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id])))
|
(let [origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id])))
|
||||||
child-set (set (get-in objects [target-frame :shapes]))
|
child-set (set (get-in objects [target-frame-id :shapes]))
|
||||||
layout? (ctl/layout? objects target-frame)
|
|
||||||
|
target-frame (get objects target-frame-id)
|
||||||
|
target-layout? (ctl/layout? target-frame)
|
||||||
|
|
||||||
|
children-ids (concat (:shapes target-frame) selected)
|
||||||
|
|
||||||
set-parent-ids
|
set-parent-ids
|
||||||
(fn [modif-tree shapes target-frame]
|
(fn [modif-tree shapes target-frame-id]
|
||||||
(reduce
|
(reduce
|
||||||
(fn [modif-tree id]
|
(fn [modif-tree id]
|
||||||
(update-in
|
(update-in
|
||||||
modif-tree
|
modif-tree
|
||||||
[id :modifiers]
|
[id :modifiers]
|
||||||
#(-> %
|
#(-> %
|
||||||
(ctm/change-property :frame-id target-frame)
|
(ctm/change-property :frame-id target-frame-id)
|
||||||
(ctm/change-property :parent-id target-frame))))
|
(ctm/change-property :parent-id target-frame-id))))
|
||||||
modif-tree
|
modif-tree
|
||||||
shapes))
|
shapes))
|
||||||
|
|
||||||
update-frame-modifiers
|
update-frame-modifiers
|
||||||
(fn [modif-tree [original-frame shapes]]
|
(fn [modif-tree [original-frame shapes]]
|
||||||
(let [shapes (->> shapes (d/removev #(= target-frame %)))
|
(let [shapes (->> shapes (d/removev #(= target-frame-id %)))
|
||||||
shapes (cond->> shapes
|
shapes (cond->> shapes
|
||||||
(and layout? (= original-frame target-frame))
|
(and target-layout? (= original-frame target-frame-id))
|
||||||
;; When movining inside a layout frame remove the shapes that are not immediate children
|
;; When movining inside a layout frame remove the shapes that are not immediate children
|
||||||
(filterv #(contains? child-set %)))]
|
(filterv #(contains? child-set %)))
|
||||||
|
children-ids (->> (dm/get-in objects [original-frame :shapes])
|
||||||
|
(remove (set selected)))
|
||||||
|
|
||||||
|
h-sizing? (ctl/change-h-sizing? original-frame objects children-ids)
|
||||||
|
v-sizing? (ctl/change-v-sizing? original-frame objects children-ids)]
|
||||||
(cond-> modif-tree
|
(cond-> modif-tree
|
||||||
(not= original-frame target-frame)
|
(not= original-frame target-frame-id)
|
||||||
(-> (modifier-remove-from-parent objects shapes)
|
(-> (modifier-remove-from-parent objects shapes)
|
||||||
(update-in [target-frame :modifiers] ctm/add-children shapes drop-index)
|
(update-in [target-frame-id :modifiers] ctm/add-children shapes drop-index)
|
||||||
(set-parent-ids shapes target-frame))
|
(set-parent-ids shapes target-frame-id)
|
||||||
|
(cond-> h-sizing?
|
||||||
|
(update-in [original-frame :modifiers] ctm/change-property :layout-item-h-sizing :fix))
|
||||||
|
(cond-> v-sizing?
|
||||||
|
(update-in [original-frame :modifiers] ctm/change-property :layout-item-v-sizing :fix)))
|
||||||
|
|
||||||
(and layout? (= original-frame target-frame))
|
(and target-layout? (= original-frame target-frame-id))
|
||||||
(update-in [target-frame :modifiers] ctm/add-children shapes drop-index))))]
|
(update-in [target-frame-id :modifiers] ctm/add-children shapes drop-index))))]
|
||||||
|
|
||||||
(reduce update-frame-modifiers modif-tree origin-frame-ids)))
|
(as-> modif-tree $
|
||||||
|
(reduce update-frame-modifiers $ origin-frame-ids)
|
||||||
|
(cond-> $
|
||||||
|
(ctl/change-h-sizing? target-frame-id objects children-ids)
|
||||||
|
(update-in [target-frame-id :modifiers] ctm/change-property :layout-item-h-sizing :fix))
|
||||||
|
(cond-> $
|
||||||
|
(ctl/change-v-sizing? target-frame-id objects children-ids)
|
||||||
|
(update-in [target-frame-id :modifiers] ctm/change-property :layout-item-v-sizing :fix)))))
|
||||||
|
|
||||||
(defn modif->js
|
(defn modif->js
|
||||||
[modif-tree objects]
|
[modif-tree objects]
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
|
||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
@ -35,12 +34,9 @@
|
||||||
(def routes
|
(def routes
|
||||||
[["/auth"
|
[["/auth"
|
||||||
["/login" :auth-login]
|
["/login" :auth-login]
|
||||||
(when (contains? @cf/flags :registration)
|
["/register" :auth-register]
|
||||||
["/register" :auth-register])
|
["/register/validate" :auth-register-validate]
|
||||||
(when (contains? @cf/flags :registration)
|
["/register/success" :auth-register-success]
|
||||||
["/register/validate" :auth-register-validate])
|
|
||||||
(when (contains? @cf/flags :registration)
|
|
||||||
["/register/success" :auth-register-success])
|
|
||||||
["/recovery/request" :auth-recovery-request]
|
["/recovery/request" :auth-recovery-request]
|
||||||
["/recovery" :auth-recovery]
|
["/recovery" :auth-recovery]
|
||||||
["/verify-token" :auth-verify-token]]
|
["/verify-token" :auth-verify-token]]
|
||||||
|
|
|
@ -84,7 +84,9 @@
|
||||||
:color (if show-text? text-color "transparent")
|
:color (if show-text? text-color "transparent")
|
||||||
:caretColor (or text-color "black")
|
:caretColor (or text-color "black")
|
||||||
:overflowWrap "initial"
|
:overflowWrap "initial"
|
||||||
:lineBreak "auto"}
|
:lineBreak "auto"
|
||||||
|
:whiteSpace "break-spaces"
|
||||||
|
:textRendering "geometricPrecision"}
|
||||||
fills
|
fills
|
||||||
(cond
|
(cond
|
||||||
(some? (:fills data))
|
(some? (:fills data))
|
||||||
|
|
|
@ -49,8 +49,8 @@
|
||||||
(st/emit! (dwm/upload-media-workspace params)))))]
|
(st/emit! (dwm/upload-media-workspace params)))))]
|
||||||
|
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image))
|
{:title (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image))
|
||||||
:aria-label (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image))
|
:aria-label (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image))
|
||||||
:on-click on-click}
|
:on-click on-click}
|
||||||
[:*
|
[:*
|
||||||
|
@ -73,8 +73,8 @@
|
||||||
[:aside.left-toolbar
|
[:aside.left-toolbar
|
||||||
[:ul.left-toolbar-options
|
[:ul.left-toolbar-options
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.move" (sc/get-tooltip :move))
|
{:title (tr "workspace.toolbar.move" (sc/get-tooltip :move))
|
||||||
:aria-label (tr "workspace.toolbar.move" (sc/get-tooltip :move))
|
:aria-label (tr "workspace.toolbar.move" (sc/get-tooltip :move))
|
||||||
:class (when (and (nil? selected-drawtool)
|
:class (when (and (nil? selected-drawtool)
|
||||||
(not edition)) "selected")
|
(not edition)) "selected")
|
||||||
|
@ -83,32 +83,32 @@
|
||||||
(when-not workspace-read-only?
|
(when-not workspace-read-only?
|
||||||
[:*
|
[:*
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
|
{:title (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
|
||||||
:aria-label (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
|
:aria-label (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
|
||||||
:class (when (= selected-drawtool :frame) "selected")
|
:class (when (= selected-drawtool :frame) "selected")
|
||||||
:on-click (partial select-drawtool :frame)
|
:on-click (partial select-drawtool :frame)
|
||||||
:data-test "artboard-btn"}
|
:data-test "artboard-btn"}
|
||||||
i/artboard]]
|
i/artboard]]
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
|
{:title (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
|
||||||
:aria-label (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
|
:aria-label (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
|
||||||
:class (when (= selected-drawtool :rect) "selected")
|
:class (when (= selected-drawtool :rect) "selected")
|
||||||
:on-click (partial select-drawtool :rect)
|
:on-click (partial select-drawtool :rect)
|
||||||
:data-test "rect-btn"}
|
:data-test "rect-btn"}
|
||||||
i/box]]
|
i/box]]
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
|
{:title (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
|
||||||
:aria-label (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
|
:aria-label (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
|
||||||
:class (when (= selected-drawtool :circle) "selected")
|
:class (when (= selected-drawtool :circle) "selected")
|
||||||
:on-click (partial select-drawtool :circle)
|
:on-click (partial select-drawtool :circle)
|
||||||
:data-test "ellipse-btn"}
|
:data-test "ellipse-btn"}
|
||||||
i/circle]]
|
i/circle]]
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
|
{:title (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
|
||||||
:aria-label (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
|
:aria-label (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
|
||||||
:class (when (= selected-drawtool :text) "selected")
|
:class (when (= selected-drawtool :text) "selected")
|
||||||
:on-click (partial select-drawtool :text)}
|
:on-click (partial select-drawtool :text)}
|
||||||
|
@ -117,16 +117,16 @@
|
||||||
[:& image-upload]
|
[:& image-upload]
|
||||||
|
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
|
{:title (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
|
||||||
:aria-label (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
|
:aria-label (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
|
||||||
:class (when (= selected-drawtool :curve) "selected")
|
:class (when (= selected-drawtool :curve) "selected")
|
||||||
:on-click (partial select-drawtool :curve)
|
:on-click (partial select-drawtool :curve)
|
||||||
:data-test "curve-btn"}
|
:data-test "curve-btn"}
|
||||||
i/pencil]]
|
i/pencil]]
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
|
{:title (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
|
||||||
:aria-label (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
|
:aria-label (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
|
||||||
:class (when (= selected-drawtool :path) "selected")
|
:class (when (= selected-drawtool :path) "selected")
|
||||||
:on-click (partial select-drawtool :path)
|
:on-click (partial select-drawtool :path)
|
||||||
|
@ -134,8 +134,8 @@
|
||||||
i/pen]]])
|
i/pen]]])
|
||||||
|
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment))
|
{:title (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment))
|
||||||
:aria-label (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment))
|
:aria-label (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment))
|
||||||
:class (when (= selected-drawtool :comments) "selected")
|
:class (when (= selected-drawtool :comments) "selected")
|
||||||
:on-click (partial select-drawtool :comments)}
|
:on-click (partial select-drawtool :comments)}
|
||||||
|
@ -145,8 +145,8 @@
|
||||||
(when-not workspace-read-only?
|
(when-not workspace-read-only?
|
||||||
[:*
|
[:*
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette))
|
{:title (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette))
|
||||||
:aria-label (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette))
|
:aria-label (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette))
|
||||||
:class (when (contains? layout :textpalette) "selected")
|
:class (when (contains? layout :textpalette) "selected")
|
||||||
:on-click (fn []
|
:on-click (fn []
|
||||||
|
@ -158,8 +158,8 @@
|
||||||
"Ag"]]
|
"Ag"]]
|
||||||
|
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette))
|
{:title (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette))
|
||||||
:aria-label (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette))
|
:aria-label (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette))
|
||||||
:class (when (contains? layout :colorpalette) "selected")
|
:class (when (contains? layout :colorpalette) "selected")
|
||||||
:on-click (fn []
|
:on-click (fn []
|
||||||
|
@ -170,8 +170,8 @@
|
||||||
(vary-meta assoc ::ev/origin "workspace-left-toolbar")))))}
|
(vary-meta assoc ::ev/origin "workspace-left-toolbar")))))}
|
||||||
i/palette]]])
|
i/palette]]])
|
||||||
[:li
|
[:li
|
||||||
[:button.tooltip.tooltip-right.separator
|
[:button
|
||||||
{:alt (tr "workspace.toolbar.shortcuts" (sc/get-tooltip :show-shortcuts))
|
{:title (tr "workspace.toolbar.shortcuts" (sc/get-tooltip :show-shortcuts))
|
||||||
:aria-label (tr "workspace.toolbar.shortcuts" (sc/get-tooltip :show-shortcuts))
|
:aria-label (tr "workspace.toolbar.shortcuts" (sc/get-tooltip :show-shortcuts))
|
||||||
:class (when (contains? layout :shortcuts) "selected")
|
:class (when (contains? layout :shortcuts) "selected")
|
||||||
:on-click (fn []
|
:on-click (fn []
|
||||||
|
@ -183,8 +183,8 @@
|
||||||
i/shortcut]
|
i/shortcut]
|
||||||
|
|
||||||
(when *assert*
|
(when *assert*
|
||||||
[:button.tooltip.tooltip-right
|
[:button
|
||||||
{:alt "Debugging tool"
|
{:title "Debugging tool"
|
||||||
:class (when (contains? layout :debug-panel) "selected")
|
:class (when (contains? layout :debug-panel) "selected")
|
||||||
:on-click (fn []
|
:on-click (fn []
|
||||||
(let [is-sidebar-closed? (contains? layout :collapse-left-sidebar)]
|
(let [is-sidebar-closed? (contains? layout :collapse-left-sidebar)]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
1.17.0
|
1.17.1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue