mirror of
https://github.com/penpot/penpot.git
synced 2026-01-12 16:28:51 -05:00
Compare commits
1 Commits
niwinz-dev
...
test-inner
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
369979ffe6 |
305
.circleci/config.yml
Normal file
305
.circleci/config.yml
Normal file
@@ -0,0 +1,305 @@
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
docker:
|
||||
- image: penpotapp/devenv:latest
|
||||
|
||||
working_directory: ~/repo
|
||||
resource_class: medium+
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: "fmt check"
|
||||
working_directory: "."
|
||||
command: |
|
||||
yarn install
|
||||
yarn run fmt:clj:check
|
||||
|
||||
- run:
|
||||
name: "lint clj common"
|
||||
working_directory: "."
|
||||
command: |
|
||||
yarn run lint:clj:common
|
||||
|
||||
- run:
|
||||
name: "lint clj frontend"
|
||||
working_directory: "."
|
||||
command: |
|
||||
yarn run lint:clj:frontend
|
||||
|
||||
- run:
|
||||
name: "lint clj backend"
|
||||
working_directory: "."
|
||||
command: |
|
||||
yarn run lint:clj:backend
|
||||
|
||||
- run:
|
||||
name: "lint clj exporter"
|
||||
working_directory: "."
|
||||
command: |
|
||||
yarn run lint:clj:exporter
|
||||
|
||||
- run:
|
||||
name: "lint clj library"
|
||||
working_directory: "."
|
||||
command: |
|
||||
yarn run lint:clj:library
|
||||
|
||||
test-common:
|
||||
docker:
|
||||
- image: penpotapp/devenv:latest
|
||||
|
||||
working_directory: ~/repo
|
||||
resource_class: medium+
|
||||
|
||||
environment:
|
||||
JAVA_OPTS: -Xmx4g -Xms100m -XX:+UseSerialGC
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "common/deps.edn"}}-{{ checksum "common/yarn.lock" }}
|
||||
|
||||
- run:
|
||||
name: "JVM tests"
|
||||
working_directory: "./common"
|
||||
command: |
|
||||
clojure -M:dev:test
|
||||
|
||||
- run:
|
||||
name: "NODE tests"
|
||||
working_directory: "./common"
|
||||
command: |
|
||||
yarn install
|
||||
yarn run test
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.m2
|
||||
- ~/.yarn
|
||||
- ~/.gitlibs
|
||||
- ~/.cache/ms-playwright
|
||||
key: v1-dependencies-{{ checksum "common/deps.edn"}}-{{ checksum "common/yarn.lock" }}
|
||||
|
||||
test-frontend:
|
||||
docker:
|
||||
- image: penpotapp/devenv:latest
|
||||
|
||||
working_directory: ~/repo
|
||||
resource_class: medium+
|
||||
|
||||
environment:
|
||||
JAVA_OPTS: -Xmx4g -Xms100m -XX:+UseSerialGC
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "frontend/deps.edn"}}-{{ checksum "frontend/yarn.lock" }}
|
||||
|
||||
- run:
|
||||
name: "install dependencies"
|
||||
working_directory: "./frontend"
|
||||
# We install playwright here because the dependent tasks
|
||||
# uses the same cache as this task so we prepopulate it
|
||||
command: |
|
||||
yarn install
|
||||
yarn run playwright install chromium --with-deps
|
||||
|
||||
- run:
|
||||
name: "lint scss on frontend"
|
||||
working_directory: "./frontend"
|
||||
command: |
|
||||
yarn run lint:scss
|
||||
|
||||
- run:
|
||||
name: "unit tests"
|
||||
working_directory: "./frontend"
|
||||
command: |
|
||||
yarn run test
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.m2
|
||||
- ~/.yarn
|
||||
- ~/.gitlibs
|
||||
- ~/.cache/ms-playwright
|
||||
key: v1-dependencies-{{ checksum "frontend/deps.edn"}}-{{ checksum "frontend/yarn.lock" }}
|
||||
|
||||
test-library:
|
||||
docker:
|
||||
- image: penpotapp/devenv:latest
|
||||
|
||||
working_directory: ~/repo
|
||||
resource_class: medium+
|
||||
|
||||
environment:
|
||||
JAVA_OPTS: -Xmx6g
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "frontend/deps.edn"}}-{{ checksum "frontend/yarn.lock" }}
|
||||
|
||||
- run:
|
||||
name: Install dependencies and build
|
||||
working_directory: "./library"
|
||||
command: |
|
||||
yarn install
|
||||
|
||||
- run:
|
||||
name: Build and Test
|
||||
working_directory: "./library"
|
||||
command: |
|
||||
./scripts/build
|
||||
yarn run test
|
||||
|
||||
test-components:
|
||||
docker:
|
||||
- image: penpotapp/devenv:latest
|
||||
|
||||
working_directory: ~/repo
|
||||
resource_class: medium+
|
||||
|
||||
environment:
|
||||
JAVA_OPTS: -Xmx6g -Xms2g
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "frontend/deps.edn"}}-{{ checksum "frontend/yarn.lock" }}
|
||||
|
||||
- run:
|
||||
name: Install dependencies
|
||||
working_directory: "./frontend"
|
||||
command: |
|
||||
yarn install
|
||||
yarn run playwright install chromium
|
||||
|
||||
- run:
|
||||
name: Build Storybook
|
||||
working_directory: "./frontend"
|
||||
command: yarn run build:storybook
|
||||
|
||||
- run:
|
||||
name: Serve Storybook and run tests
|
||||
working_directory: "./frontend"
|
||||
command: |
|
||||
npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
|
||||
"npx http-server storybook-static --port 6006 --silent" \
|
||||
"npx wait-on tcp:6006 && yarn test:storybook"
|
||||
|
||||
test-backend:
|
||||
docker:
|
||||
- image: penpotapp/devenv:latest
|
||||
- image: cimg/postgres:14.5
|
||||
environment:
|
||||
POSTGRES_USER: penpot_test
|
||||
POSTGRES_PASSWORD: penpot_test
|
||||
POSTGRES_DB: penpot_test
|
||||
- image: cimg/redis:7.0.5
|
||||
|
||||
working_directory: ~/repo
|
||||
resource_class: medium+
|
||||
|
||||
environment:
|
||||
JAVA_OPTS: -Xmx4g -Xms100m -XX:+UseSerialGC
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "backend/deps.edn" }}
|
||||
|
||||
- run:
|
||||
name: "tests"
|
||||
working_directory: "./backend"
|
||||
command: |
|
||||
clojure -M:dev:test --reporter kaocha.report/documentation
|
||||
|
||||
environment:
|
||||
PENPOT_TEST_DATABASE_URI: "postgresql://localhost/penpot_test"
|
||||
PENPOT_TEST_DATABASE_USERNAME: penpot_test
|
||||
PENPOT_TEST_DATABASE_PASSWORD: penpot_test
|
||||
PENPOT_TEST_REDIS_URI: "redis://localhost/1"
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.m2
|
||||
- ~/.gitlibs
|
||||
key: v1-dependencies-{{ checksum "backend/deps.edn" }}
|
||||
|
||||
test-render-wasm:
|
||||
docker:
|
||||
- image: penpotapp/devenv:latest
|
||||
|
||||
working_directory: ~/repo
|
||||
resource_class: medium+
|
||||
environment:
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: "fmt check"
|
||||
working_directory: "./render-wasm"
|
||||
command: |
|
||||
cargo fmt --check
|
||||
|
||||
- run:
|
||||
name: "lint"
|
||||
working_directory: "./render-wasm"
|
||||
command: |
|
||||
./lint
|
||||
|
||||
- run:
|
||||
name: "cargo tests"
|
||||
working_directory: "./render-wasm"
|
||||
command: |
|
||||
./test
|
||||
|
||||
workflows:
|
||||
penpot:
|
||||
jobs:
|
||||
- test-frontend:
|
||||
requires:
|
||||
- lint: success
|
||||
|
||||
- test-library:
|
||||
requires:
|
||||
- lint: success
|
||||
|
||||
- test-components:
|
||||
requires:
|
||||
- lint: success
|
||||
|
||||
- test-backend:
|
||||
requires:
|
||||
- lint: success
|
||||
|
||||
- test-common:
|
||||
requires:
|
||||
- lint: success
|
||||
|
||||
- lint
|
||||
- test-render-wasm
|
||||
15
.github/workflows/build-tag.yml
vendored
15
.github/workflows/build-tag.yml
vendored
@@ -21,21 +21,6 @@ jobs:
|
||||
with:
|
||||
gh_ref: ${{ github.ref_name }}
|
||||
|
||||
notify:
|
||||
name: Notifications
|
||||
needs: build-docker
|
||||
|
||||
steps:
|
||||
- name: Notify Mattermost
|
||||
uses: mattermost/action-mattermost-notify@master
|
||||
with:
|
||||
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK }}
|
||||
MATTERMOST_CHANNEL: bot-alerts-cicd
|
||||
TEXT: |
|
||||
🐳 *[PENPOT] Docker image available.*
|
||||
🔗 Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
@infra
|
||||
|
||||
publish-final-tag:
|
||||
if: ${{ !contains(github.ref_name, '-RC') && !contains(github.ref_name, '-alpha') && !contains(github.ref_name, '-beta') && contains(github.ref_name, '.') }}
|
||||
needs: build-docker
|
||||
|
||||
96
.github/workflows/tests.yml
vendored
96
.github/workflows/tests.yml
vendored
@@ -8,6 +8,8 @@ on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- reopened
|
||||
- synchronize
|
||||
push:
|
||||
branches:
|
||||
@@ -15,12 +17,12 @@ on:
|
||||
- staging
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.event.pull_request.number || github.ref }}
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: "Linter"
|
||||
name: "Code Linter"
|
||||
runs-on: ubuntu-24.04
|
||||
container: penpotapp/devenv:latest
|
||||
|
||||
@@ -30,7 +32,10 @@ jobs:
|
||||
|
||||
- name: Check clojure code format
|
||||
run: |
|
||||
./scripts/lint
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install
|
||||
yarn run fmt:clj:check
|
||||
|
||||
test-common:
|
||||
name: "Common Tests"
|
||||
@@ -49,7 +54,10 @@ jobs:
|
||||
- name: Run tests on NODE
|
||||
working-directory: ./common
|
||||
run: |
|
||||
./scripts/test
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
yarn run test;
|
||||
|
||||
test-frontend:
|
||||
name: "Frontend Tests"
|
||||
@@ -63,36 +71,25 @@ jobs:
|
||||
- name: Unit Tests
|
||||
working-directory: ./frontend
|
||||
run: |
|
||||
./scripts/test
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
yarn run test;
|
||||
|
||||
- name: Component Tests
|
||||
working-directory: ./frontend
|
||||
run: |
|
||||
./scripts/test-components
|
||||
yarn run playwright install chromium --with-deps;
|
||||
yarn run build:storybook
|
||||
|
||||
test-render-wasm:
|
||||
name: "Render WASM Tests"
|
||||
runs-on: ubuntu-24.04
|
||||
container: penpotapp/devenv:latest
|
||||
npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
|
||||
"npx http-server storybook-static --port 6006 --silent" \
|
||||
"npx wait-on tcp:6006 && yarn test:storybook"
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Format
|
||||
working-directory: ./render-wasm
|
||||
- name: Check SCSS Format
|
||||
working-directory: ./frontend
|
||||
run: |
|
||||
cargo fmt --check
|
||||
|
||||
- name: Lint
|
||||
working-directory: ./render-wasm
|
||||
run: |
|
||||
./lint
|
||||
|
||||
- name: Test
|
||||
working-directory: ./render-wasm
|
||||
run: |
|
||||
./test
|
||||
yarn run lint:scss;
|
||||
|
||||
test-backend:
|
||||
name: "Backend Tests"
|
||||
@@ -145,7 +142,11 @@ jobs:
|
||||
- name: Run tests
|
||||
working-directory: ./library
|
||||
run: |
|
||||
./scripts/test
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
yarn run build:bundle;
|
||||
yarn run test;
|
||||
|
||||
build-integration:
|
||||
name: "Build Integration Bundle"
|
||||
@@ -159,7 +160,17 @@ jobs:
|
||||
- name: Build Bundle
|
||||
working-directory: ./frontend
|
||||
run: |
|
||||
./scripts/build 0.0.0
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install
|
||||
yarn run build:app:assets
|
||||
yarn run build:app
|
||||
yarn run build:app:libs
|
||||
|
||||
- name: Build WASM
|
||||
working-directory: "./render-wasm"
|
||||
run: |
|
||||
./build release
|
||||
|
||||
- name: Store Bundle Cache
|
||||
uses: actions/cache@v4
|
||||
@@ -167,7 +178,6 @@ jobs:
|
||||
key: "integration-bundle-${{ github.sha }}"
|
||||
path: frontend/resources/public
|
||||
|
||||
|
||||
test-integration-1:
|
||||
name: "Integration Tests 1/4"
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -187,7 +197,11 @@ jobs:
|
||||
- name: Run Tests
|
||||
working-directory: ./frontend
|
||||
run: |
|
||||
./scripts/test-e2e --shard="1/4";
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
yarn run playwright install chromium --with-deps;
|
||||
yarn run test:e2e -x --workers=2 --reporter=list --shard="1/4";
|
||||
|
||||
- name: Upload test result
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -217,7 +231,11 @@ jobs:
|
||||
- name: Run Tests
|
||||
working-directory: ./frontend
|
||||
run: |
|
||||
./scripts/test-e2e --shard="2/4";
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
yarn run playwright install chromium --with-deps;
|
||||
yarn run test:e2e -x --workers=2 --reporter=list --shard "2/4";
|
||||
|
||||
- name: Upload test result
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -247,7 +265,11 @@ jobs:
|
||||
- name: Run Tests
|
||||
working-directory: ./frontend
|
||||
run: |
|
||||
./scripts/test-e2e --shard="3/4";
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
yarn run playwright install chromium --with-deps;
|
||||
yarn run test:e2e -x --workers=2 --reporter=list --shard "3/4";
|
||||
|
||||
- name: Upload test result
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -259,7 +281,7 @@ jobs:
|
||||
retention-days: 3
|
||||
|
||||
test-integration-4:
|
||||
name: "Integration Tests 4/4"
|
||||
name: "Integration Tests 3/4"
|
||||
runs-on: ubuntu-24.04
|
||||
container: penpotapp/devenv:latest
|
||||
needs: build-integration
|
||||
@@ -277,7 +299,11 @@ jobs:
|
||||
- name: Run Tests
|
||||
working-directory: ./frontend
|
||||
run: |
|
||||
./scripts/test-e2e --shard="4/4";
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
yarn run playwright install chromium --with-deps;
|
||||
yarn run test:e2e -x --workers=2 --reporter=list --shard "4/4";
|
||||
|
||||
- name: Upload test result
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -80,4 +80,3 @@ node_modules
|
||||
/playwright/.cache/
|
||||
/render-wasm/target/
|
||||
/**/.yarn/*
|
||||
/.pnpm-store
|
||||
13
CHANGES.md
13
CHANGES.md
@@ -1,18 +1,5 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 2.13.0 (Unreleased)
|
||||
|
||||
### :boom: Breaking changes & Deprecations
|
||||
|
||||
### :rocket: Epics and highlights
|
||||
|
||||
### :heart: Community contributions (Thank you!)
|
||||
|
||||
### :sparkles: New features & Enhancements
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
|
||||
## 2.12.0 (Unreleased)
|
||||
|
||||
### :boom: Breaking changes & Deprecations
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
From: {{profile.fullname}} <{{profile.email}}> / {{profile.id}}
|
||||
Subject: {{feedback-subject}}
|
||||
Type: {{feedback-type}}
|
||||
|
||||
{% if feedback-error-href %}
|
||||
{%- if feedback-error-href %}
|
||||
HREF: {{feedback-error-href}}
|
||||
{% endif -%}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
:uid uuid/zero})
|
||||
body (t/encode {:events events})
|
||||
headers {"content-type" "application/transit+json"
|
||||
"origin" (str (cf/get :public-uri))
|
||||
"origin" (cf/get :public-uri)
|
||||
"cookie" (u/map->query-string {:auth-token token})}
|
||||
params {:uri uri
|
||||
:timeout 12000
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
[app.common.exceptions :as ex]
|
||||
[selmer.parser :as sp]))
|
||||
|
||||
;; (sp/cache-off!)
|
||||
(sp/cache-off!)
|
||||
|
||||
(defn render
|
||||
[path context]
|
||||
|
||||
@@ -318,35 +318,3 @@
|
||||
;; check that we have all no objects
|
||||
(let [rows (th/db-exec! ["select * from storage_object where deleted_at is null"])]
|
||||
(t/is (= 0 (count rows))))))
|
||||
|
||||
(t/deftest tempfile-bucket-test
|
||||
(let [storage (-> (:app.storage/storage th/*system*)
|
||||
(configure-storage-backend))
|
||||
content1 (sto/content "content1")
|
||||
now (ct/now)
|
||||
|
||||
object1 (sto/put-object! storage {::sto/content content1
|
||||
::sto/touched-at (ct/plus now {:minutes 1})
|
||||
:bucket "tempfile"
|
||||
:content-type "text/plain"})]
|
||||
|
||||
|
||||
(binding [ct/*clock* (clock/fixed now)]
|
||||
(let [res (th/run-task! :storage-gc-touched {})]
|
||||
(t/is (= 0 (:freeze res)))
|
||||
(t/is (= 0 (:delete res)))))
|
||||
|
||||
|
||||
(binding [ct/*clock* (clock/fixed (ct/plus now {:minutes 1}))]
|
||||
(let [res (th/run-task! :storage-gc-touched {})]
|
||||
(t/is (= 0 (:freeze res)))
|
||||
(t/is (= 1 (:delete res)))))
|
||||
|
||||
|
||||
(binding [ct/*clock* (clock/fixed (ct/plus now {:hours 1}))]
|
||||
(let [res (th/run-task! :storage-gc-deleted {})]
|
||||
(t/is (= 0 (:deleted res)))))
|
||||
|
||||
(binding [ct/*clock* (clock/fixed (ct/plus now {:hours 2}))]
|
||||
(let [res (th/run-task! :storage-gc-deleted {})]
|
||||
(t/is (= 0 (:deleted res)))))))
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
org.slf4j/slf4j-api {:mvn/version "2.0.17"}
|
||||
pl.tkowalcz.tjahzi/log4j2-appender {:mvn/version "0.9.40"}
|
||||
|
||||
selmer/selmer {:mvn/version "1.12.69"}
|
||||
selmer/selmer {:mvn/version "1.12.62"}
|
||||
criterium/criterium {:mvn/version "0.4.6"}
|
||||
|
||||
metosin/jsonista {:mvn/version "0.3.13"}
|
||||
@@ -29,6 +29,7 @@
|
||||
java-http-clj/java-http-clj {:mvn/version "0.4.3"}
|
||||
integrant/integrant {:mvn/version "1.0.0"}
|
||||
|
||||
funcool/tubax {:mvn/version "2021.05.20-0"}
|
||||
funcool/cuerdas {:mvn/version "2025.06.16-414"}
|
||||
funcool/promesa
|
||||
{:git/sha "46048fc0d4bf5466a2a4121f5d52aefa6337f2e8"
|
||||
@@ -47,8 +48,12 @@
|
||||
com.sun.mail/jakarta.mail {:mvn/version "2.0.2"}
|
||||
org.la4j/la4j {:mvn/version "0.6.0"}
|
||||
|
||||
;; exception printing
|
||||
fipp/fipp {:mvn/version "0.6.29"}
|
||||
|
||||
me.flowthing/pp {:mvn/version "2024-11-13.77"}
|
||||
|
||||
|
||||
io.aviso/pretty {:mvn/version "1.4.4"}
|
||||
environ/environ {:mvn/version "1.2.0"}}
|
||||
:paths ["src" "vendor" "target/classes"]
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
yarn run test;
|
||||
@@ -9,10 +9,10 @@
|
||||
(:refer-clojure :exclude [get-in select-keys str with-open max])
|
||||
#?(:cljs (:require-macros [app.common.data.macros]))
|
||||
(:require
|
||||
#?(:clj [cljs.analyzer.api :as aapi])
|
||||
#?(:clj [clojure.core :as c]
|
||||
:cljs [cljs.core :as c])
|
||||
[app.common.data :as d]
|
||||
[cljs.analyzer.api :as aapi]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(defmacro select-keys
|
||||
@@ -44,43 +44,42 @@
|
||||
[& params]
|
||||
`(str/concat ~@params))
|
||||
|
||||
#?(:clj
|
||||
(defmacro export
|
||||
"A helper macro that allows reexport a var in a current namespace."
|
||||
[v]
|
||||
(if (boolean (:ns &env))
|
||||
(defmacro export
|
||||
"A helper macro that allows reexport a var in a current namespace."
|
||||
[v]
|
||||
(if (boolean (:ns &env))
|
||||
|
||||
;; Code for ClojureScript
|
||||
(let [mdata (aapi/resolve &env v)
|
||||
arglists (second (get-in mdata [:meta :arglists]))
|
||||
sym (symbol (c/name v))
|
||||
andsym (symbol "&")
|
||||
procarg #(if (= % andsym) % (gensym "param"))]
|
||||
(if (pos? (count arglists))
|
||||
`(def
|
||||
~(with-meta sym (:meta mdata))
|
||||
(fn ~@(for [args arglists]
|
||||
(let [args (map procarg args)]
|
||||
(if (some #(= andsym %) args)
|
||||
(let [[sargs dargs] (split-with #(not= andsym %) args)]
|
||||
`([~@sargs ~@dargs] (apply ~v ~@sargs ~@(rest dargs))))
|
||||
`([~@args] (~v ~@args)))))))
|
||||
`(def ~(with-meta sym (:meta mdata)) ~v)))
|
||||
;; Code for ClojureScript
|
||||
(let [mdata (aapi/resolve &env v)
|
||||
arglists (second (get-in mdata [:meta :arglists]))
|
||||
sym (symbol (c/name v))
|
||||
andsym (symbol "&")
|
||||
procarg #(if (= % andsym) % (gensym "param"))]
|
||||
(if (pos? (count arglists))
|
||||
`(def
|
||||
~(with-meta sym (:meta mdata))
|
||||
(fn ~@(for [args arglists]
|
||||
(let [args (map procarg args)]
|
||||
(if (some #(= andsym %) args)
|
||||
(let [[sargs dargs] (split-with #(not= andsym %) args)]
|
||||
`([~@sargs ~@dargs] (apply ~v ~@sargs ~@(rest dargs))))
|
||||
`([~@args] (~v ~@args)))))))
|
||||
`(def ~(with-meta sym (:meta mdata)) ~v)))
|
||||
|
||||
;; Code for Clojure
|
||||
(let [vr (resolve v)
|
||||
m (meta vr)
|
||||
n (:name m)
|
||||
n (with-meta n
|
||||
(cond-> {}
|
||||
(:dynamic m) (assoc :dynamic true)
|
||||
(:protocol m) (assoc :protocol (:protocol m))))]
|
||||
`(let [m# (meta ~vr)]
|
||||
(def ~n (deref ~vr))
|
||||
(alter-meta! (var ~n) merge (dissoc m# :name))
|
||||
;; (when (:macro m#)
|
||||
;; (.setMacro (var ~n)))
|
||||
~vr)))))
|
||||
;; Code for Clojure
|
||||
(let [vr (resolve v)
|
||||
m (meta vr)
|
||||
n (:name m)
|
||||
n (with-meta n
|
||||
(cond-> {}
|
||||
(:dynamic m) (assoc :dynamic true)
|
||||
(:protocol m) (assoc :protocol (:protocol m))))]
|
||||
`(let [m# (meta ~vr)]
|
||||
(def ~n (deref ~vr))
|
||||
(alter-meta! (var ~n) merge (dissoc m# :name))
|
||||
;; (when (:macro m#)
|
||||
;; (.setMacro (var ~n)))
|
||||
~vr))))
|
||||
|
||||
(defmacro fmt
|
||||
"String interpolation helper. Can only be used with strings known at
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
[app.common.schema :as sm]
|
||||
[clojure.core :as c]
|
||||
[clojure.spec.alpha :as s]
|
||||
[cuerdas.core :as str])
|
||||
[cuerdas.core :as str]
|
||||
[expound.alpha :as expound])
|
||||
#?(:clj
|
||||
(:import
|
||||
clojure.lang.IPersistentMap)))
|
||||
@@ -109,6 +110,13 @@
|
||||
(contains? data :explain))
|
||||
(explain (:explain data) opts)
|
||||
|
||||
(and (contains? data ::s/problems)
|
||||
(contains? data ::s/value)
|
||||
(contains? data ::s/spec))
|
||||
(binding [s/*explain-out* expound/printer]
|
||||
(with-out-str
|
||||
(s/explain-out (update data ::s/problems #(take (:length opts 10) %)))))
|
||||
|
||||
(contains? data ::sm/explain)
|
||||
(sm/humanize-explain (::sm/explain data) opts)))
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
"
|
||||
#?(:cljs (:require-macros [app.common.logging :as l]))
|
||||
(:require
|
||||
#?(:clj [clojure.edn :as edn]
|
||||
:cljs [cljs.reader :as edn])
|
||||
[app.common.data :as d]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.pprint :as pp]
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
[app.common.logic.shapes :as cls]
|
||||
[app.common.logic.variant-properties :as clvp]
|
||||
[app.common.path-names :as cpn]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.container :as ctn]
|
||||
@@ -34,7 +35,8 @@
|
||||
[app.common.types.typography :as cty]
|
||||
[app.common.types.variant :as ctv]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.set :as set]))
|
||||
[clojure.set :as set]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
;; Change this to :info :debug or :trace to debug this module, or :warn to reset to default
|
||||
(log/set-level! :warn)
|
||||
@@ -471,10 +473,10 @@
|
||||
If an asset id is given, only shapes linked to this particular asset will
|
||||
be synchronized."
|
||||
[changes file-id asset-type asset-id library-id libraries current-file-id]
|
||||
(assert (contains? #{:colors :components :typographies} asset-type))
|
||||
(assert (or (nil? asset-id) (uuid? asset-id)))
|
||||
(assert (uuid? file-id))
|
||||
(assert (uuid? library-id))
|
||||
(s/assert #{:colors :components :typographies} asset-type)
|
||||
(s/assert (s/nilable ::us/uuid) asset-id)
|
||||
(s/assert ::us/uuid file-id)
|
||||
(s/assert ::us/uuid library-id)
|
||||
|
||||
(container-log :info asset-id
|
||||
:msg "Sync file with library"
|
||||
@@ -508,10 +510,10 @@
|
||||
If an asset id is given, only shapes linked to this particular asset will
|
||||
be synchronized."
|
||||
[changes file-id asset-type asset-id library-id libraries current-file-id]
|
||||
(assert (contains? #{:colors :components :typographies} asset-type))
|
||||
(assert (or (nil? asset-id) (uuid? asset-id)))
|
||||
(assert (uuid? file-id))
|
||||
(assert (uuid? library-id))
|
||||
(s/assert #{:colors :components :typographies} asset-type)
|
||||
(s/assert (s/nilable ::us/uuid) asset-id)
|
||||
(s/assert ::us/uuid file-id)
|
||||
(s/assert ::us/uuid library-id)
|
||||
|
||||
(container-log :info asset-id
|
||||
:msg "Sync local components with library"
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
(:refer-clojure :exclude [deref merge parse-uuid parse-long parse-double parse-boolean type keys])
|
||||
#?(:cljs (:require-macros [app.common.schema :refer [ignoring]]))
|
||||
(:require
|
||||
#?(:clj [malli.dev.pretty :as mdp])
|
||||
#?(:clj [malli.dev.virhe :as v])
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pprint :as pp]
|
||||
@@ -21,6 +19,8 @@
|
||||
[clojure.core :as c]
|
||||
[cuerdas.core :as str]
|
||||
[malli.core :as m]
|
||||
[malli.dev.pretty :as mdp]
|
||||
[malli.dev.virhe :as v]
|
||||
[malli.error :as me]
|
||||
[malli.generator :as mg]
|
||||
[malli.registry :as mr]
|
||||
@@ -245,30 +245,27 @@
|
||||
:level (d/nilv level 8)
|
||||
:length (d/nilv length 12)})))))
|
||||
|
||||
#?(:clj
|
||||
(defmethod v/-format ::schemaless-explain
|
||||
[_ explanation printer]
|
||||
{:body [:group
|
||||
(v/-block "Value" (v/-visit (me/error-value explanation printer) printer) printer) :break :break
|
||||
(v/-block "Errors" (v/-visit (me/humanize (me/with-spell-checking explanation)) printer) printer)]}))
|
||||
(defmethod v/-format ::schemaless-explain
|
||||
[_ explanation printer]
|
||||
{:body [:group
|
||||
(v/-block "Value" (v/-visit (me/error-value explanation printer) printer) printer) :break :break
|
||||
(v/-block "Errors" (v/-visit (me/humanize (me/with-spell-checking explanation)) printer) printer)]})
|
||||
|
||||
#?(:clj
|
||||
(defmethod v/-format ::explain
|
||||
[_ {:keys [schema] :as explanation} printer]
|
||||
{:body [:group
|
||||
(v/-block "Value" (v/-visit (me/error-value explanation printer) printer) printer) :break :break
|
||||
(v/-block "Errors" (v/-visit (me/humanize (me/with-spell-checking explanation)) printer) printer) :break :break
|
||||
(v/-block "Schema" (v/-visit schema printer) printer)]}))
|
||||
(defmethod v/-format ::explain
|
||||
[_ {:keys [schema] :as explanation} printer]
|
||||
{:body [:group
|
||||
(v/-block "Value" (v/-visit (me/error-value explanation printer) printer) printer) :break :break
|
||||
(v/-block "Errors" (v/-visit (me/humanize (me/with-spell-checking explanation)) printer) printer) :break :break
|
||||
(v/-block "Schema" (v/-visit schema printer) printer)]})
|
||||
|
||||
#?(:clj
|
||||
(defn pretty-explain
|
||||
"A helper that allows print a console-friendly output for the explain;
|
||||
should not be used for other purposes"
|
||||
[explain & {:keys [variant message]
|
||||
:or {variant ::explain
|
||||
message "Validation Error"}}]
|
||||
(let [explain (fn [] (me/with-error-messages explain))]
|
||||
((mdp/prettifier variant message explain default-options)))))
|
||||
(defn pretty-explain
|
||||
"A helper that allows print a console-friendly output for the
|
||||
explain; should not be used for other purposes"
|
||||
[explain & {:keys [variant message]
|
||||
:or {variant ::explain
|
||||
message "Validation Error"}}]
|
||||
(let [explain (fn [] (me/with-error-messages explain))]
|
||||
((mdp/prettifier variant message explain default-options))))
|
||||
|
||||
(defmacro ignoring
|
||||
[expr]
|
||||
@@ -302,13 +299,6 @@
|
||||
::explain explain}))))
|
||||
value))))
|
||||
|
||||
(defn coercer
|
||||
[schema & {:as opts}]
|
||||
(let [decode-fn (decoder schema json-transformer)
|
||||
check-fn (check-fn schema opts)]
|
||||
(fn [data]
|
||||
(-> data decode-fn check-fn))))
|
||||
|
||||
(defn check
|
||||
"A helper intended to be used on assertions for validate/check the
|
||||
schema over provided data. Raises an assertion exception.
|
||||
@@ -852,6 +842,38 @@
|
||||
choices))]
|
||||
{:pred pred}))})
|
||||
|
||||
;; (register!
|
||||
;; {:type ::inst
|
||||
;; :pred tm/instant?
|
||||
;; :type-properties
|
||||
;; {:title "inst"
|
||||
;; :description "Satisfies Inst protocol"
|
||||
;; :error/message "should be an instant"
|
||||
;; :gen/gen (->> (sg/small-int :min 0 :max 100000)
|
||||
;; (sg/fmap (fn [v] (tm/parse-inst v))))
|
||||
|
||||
;; :decode/string tm/parse-inst
|
||||
;; :encode/string tm/format-inst
|
||||
;; :decode/json tm/parse-inst
|
||||
;; :encode/json tm/format-inst
|
||||
;; ::oapi/type "string"
|
||||
;; ::oapi/format "iso"}})
|
||||
|
||||
;; (register!
|
||||
;; {:type ::timestamp
|
||||
;; :pred tm/instant?
|
||||
;; :type-properties
|
||||
;; {:title "inst"
|
||||
;; :description "Satisfies Inst protocol, the same as ::inst but encodes to epoch"
|
||||
;; :error/message "should be an instant"
|
||||
;; :gen/gen (->> (sg/small-int)
|
||||
;; (sg/fmap (fn [v] (tm/parse-inst v))))
|
||||
;; :decode/string tm/parse-inst
|
||||
;; :encode/string inst-ms
|
||||
;; :decode/json tm/parse-inst
|
||||
;; :encode/json inst-ms
|
||||
;; ::oapi/type "string"
|
||||
;; ::oapi/format "number"}})
|
||||
|
||||
#?(:clj
|
||||
(register!
|
||||
@@ -929,7 +951,7 @@
|
||||
:pred #(and (string? %) (not (str/blank? %)))
|
||||
:property-pred
|
||||
(fn [{:keys [min max] :as props}]
|
||||
(if (or min max)
|
||||
(if (seq props)
|
||||
(fn [value]
|
||||
(let [size (count value)]
|
||||
(cond
|
||||
@@ -1003,9 +1025,6 @@
|
||||
(def valid-safe-number?
|
||||
(lazy-validator ::safe-number))
|
||||
|
||||
(def valid-safe-int?
|
||||
(lazy-validator ::safe-int))
|
||||
|
||||
(def valid-text?
|
||||
(validator ::text))
|
||||
|
||||
|
||||
@@ -25,6 +25,48 @@ RUN set -ex; \
|
||||
binutils \
|
||||
build-essential autoconf libtool pkg-config
|
||||
|
||||
|
||||
################################################################################
|
||||
## IMAGE MAGICK
|
||||
################################################################################
|
||||
|
||||
FROM base AS build-imagemagick
|
||||
|
||||
ENV IMAGEMAGICK_VERSION=7.1.1-47 \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN set -ex; \
|
||||
apt-get -qq update; \
|
||||
apt-get -qq upgrade; \
|
||||
apt-get -qqy --no-install-recommends install \
|
||||
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 \
|
||||
; \
|
||||
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;
|
||||
|
||||
################################################################################
|
||||
## NODE SETUP
|
||||
################################################################################
|
||||
@@ -65,7 +107,7 @@ RUN set -eux; \
|
||||
|
||||
FROM base AS setup-jvm
|
||||
|
||||
ENV CLOJURE_VERSION=1.12.3.1577
|
||||
ENV CLOJURE_VERSION=1.12.2.1565
|
||||
|
||||
RUN set -eux; \
|
||||
ARCH="$(dpkg --print-architecture)"; \
|
||||
@@ -343,7 +385,7 @@ ENV LANG='C.UTF-8' \
|
||||
RUSTUP_HOME="/opt/rustup" \
|
||||
PATH="/opt/jdk/bin:/opt/utils/bin:/opt/clojure/bin:/opt/node/bin:/opt/imagick/bin:/opt/cargo/bin:$PATH"
|
||||
|
||||
COPY --from=penpotapp/imagemagick:7.1.2-0 /opt/imagick /opt/imagick
|
||||
COPY --from=build-imagemagick /opt/imagick /opt/imagick
|
||||
COPY --from=setup-jvm /opt/jdk /opt/jdk
|
||||
COPY --from=setup-jvm /opt/clojure /opt/clojure
|
||||
COPY --from=setup-node /opt/node /opt/node
|
||||
|
||||
@@ -67,11 +67,6 @@ services:
|
||||
- PENPOT_LDAP_ATTRS_FULLNAME=cn
|
||||
- PENPOT_LDAP_ATTRS_PHOTO=jpegPhoto
|
||||
|
||||
networks:
|
||||
default:
|
||||
aliases:
|
||||
- main
|
||||
|
||||
minio:
|
||||
image: "minio/minio:RELEASE.2025-04-03T14-56-28Z"
|
||||
command: minio server /mnt/data --console-address ":9001"
|
||||
@@ -83,6 +78,10 @@ services:
|
||||
- MINIO_ROOT_USER=minioadmin
|
||||
- MINIO_ROOT_PASSWORD=minioadmin
|
||||
|
||||
ports:
|
||||
- 9000:9000
|
||||
- 9001:9001
|
||||
|
||||
networks:
|
||||
default:
|
||||
aliases:
|
||||
|
||||
@@ -12,7 +12,7 @@ http {
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 0;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
server_tokens off;
|
||||
|
||||
@@ -223,6 +223,16 @@ http {
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
}
|
||||
|
||||
location ~ ^/js/config.js$ {
|
||||
add_header Cache-Control "no-store, no-cache, max-age=0" always;
|
||||
}
|
||||
|
||||
location ~* \.(js|css|jpg|svg|png|mjs|map)$ {
|
||||
# We set no cache only on devenv
|
||||
add_header Cache-Control "no-store, no-cache, max-age=0" always;
|
||||
# add_header Cache-Control "max-age=604800" always; # 7 days
|
||||
}
|
||||
|
||||
location ~ ^/(/|css|fonts|images|js|wasm|mjs|map) {
|
||||
}
|
||||
|
||||
@@ -230,10 +240,9 @@ http {
|
||||
return 301 " /404";
|
||||
}
|
||||
|
||||
add_header Cache-Control "no-store";
|
||||
add_header Connection close always;
|
||||
# This header is what we need to use on prod
|
||||
# add_header Cache-Control "public, must-revalidate, max-age=0";
|
||||
add_header Last-Modified $date_gmt;
|
||||
add_header Cache-Control "no-store, no-cache, max-age=0" always;
|
||||
if_modified_since off;
|
||||
try_files $uri /index.html$is_args$args /index.html =404;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
@@ -107,25 +107,6 @@ desc: Streamline your design workflow with Penpot's Components guide! Learn to c
|
||||
<li>Select the variant copy, press right-click, and select the menu option <strong>Restore variant</strong> (will show if the main component still exists).</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="component-variants-toggle">Toggle for boolean variants</h3>
|
||||
<p>When a variant property represents a boolean state, Penpot can display it as a toggle instead of a dropdown. This offers a quicker and more visual way to switch between two opposite values when working with copies.</p>
|
||||
<p>The toggle appears in place of the property values dropdown, <strong>only when a copy is selected</strong>.</p>
|
||||
<figure>
|
||||
<img src="/img/variants/07-variants-boolean.webp" alt="Boolean variant option" />
|
||||
</figure>
|
||||
<h4>Accepted value pairs</h4>
|
||||
<p>For Penpot to recognize the property as a boolean and display the toggle, the property must be defined with exactly two opposing values. These can be any of the following pairs:</p>
|
||||
<ul>
|
||||
<li><code>true</code> / <code>false</code></li>
|
||||
<li><code>on</code> / <code>off</code></li>
|
||||
<li><code>yes</code> / <code>no</code></li>
|
||||
</ul>
|
||||
<p>The order of the values does not matter. Penpot automatically maps them to ON and OFF states:</p>
|
||||
<ul>
|
||||
<li><strong>ON state:</strong> <code>true</code>, <code>yes</code>, <code>on</code></li>
|
||||
<li><strong>OFF state:</strong> <code>false</code>, <code>no</code>, <code>off</code></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="component-use-variants">Use variants</h3>
|
||||
<p>Once you have created your variants, you can place a copy of a component with variants into your design and then switch between its different versions.</p>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"license": "MPL-2.0",
|
||||
"author": "Kaleidos INC",
|
||||
"private": true,
|
||||
"packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8",
|
||||
"packageManager": "yarn@4.10.3+sha512.c38cafb5c7bb273f3926d04e55e1d8c9dfa7d9c3ea1f36a4868fa028b9e5f72298f0b7f401ad5eb921749eb012eb1c3bb74bf7503df3ee43fd600d14a018266f",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/penpot/penpot"
|
||||
@@ -16,9 +16,9 @@
|
||||
"date-fns": "^4.1.0",
|
||||
"generic-pool": "^3.9.0",
|
||||
"inflation": "^2.1.0",
|
||||
"ioredis": "^5.8.2",
|
||||
"playwright": "^1.57.0",
|
||||
"raw-body": "^3.0.2",
|
||||
"ioredis": "^5.8.1",
|
||||
"playwright": "^1.55.1",
|
||||
"raw-body": "^3.0.1",
|
||||
"source-map-support": "^0.5.21",
|
||||
"svgo": "penpot/svgo#v3.1",
|
||||
"xml-js": "^1.6.11",
|
||||
|
||||
@@ -243,7 +243,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bytes@npm:~3.1.2":
|
||||
"bytes@npm:3.1.2":
|
||||
version: 3.1.2
|
||||
resolution: "bytes@npm:3.1.2"
|
||||
checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e
|
||||
@@ -442,7 +442,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"depd@npm:~2.0.0":
|
||||
"depd@npm:2.0.0, depd@npm:~2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "depd@npm:2.0.0"
|
||||
checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c
|
||||
@@ -577,9 +577,9 @@ __metadata:
|
||||
date-fns: "npm:^4.1.0"
|
||||
generic-pool: "npm:^3.9.0"
|
||||
inflation: "npm:^2.1.0"
|
||||
ioredis: "npm:^5.8.2"
|
||||
playwright: "npm:^1.57.0"
|
||||
raw-body: "npm:^3.0.2"
|
||||
ioredis: "npm:^5.8.1"
|
||||
playwright: "npm:^1.55.1"
|
||||
raw-body: "npm:^3.0.1"
|
||||
source-map-support: "npm:^0.5.21"
|
||||
svgo: "penpot/svgo#v3.1"
|
||||
ws: "npm:^8.18.3"
|
||||
@@ -682,16 +682,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"http-errors@npm:~2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "http-errors@npm:2.0.1"
|
||||
"http-errors@npm:2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "http-errors@npm:2.0.0"
|
||||
dependencies:
|
||||
depd: "npm:~2.0.0"
|
||||
inherits: "npm:~2.0.4"
|
||||
setprototypeof: "npm:~1.2.0"
|
||||
statuses: "npm:~2.0.2"
|
||||
toidentifier: "npm:~1.0.1"
|
||||
checksum: 10c0/fb38906cef4f5c83952d97661fe14dc156cb59fe54812a42cd448fa57b5c5dfcb38a40a916957737bd6b87aab257c0648d63eb5b6a9ca9f548e105b6072712d4
|
||||
depd: "npm:2.0.0"
|
||||
inherits: "npm:2.0.4"
|
||||
setprototypeof: "npm:1.2.0"
|
||||
statuses: "npm:2.0.1"
|
||||
toidentifier: "npm:1.0.1"
|
||||
checksum: 10c0/fc6f2715fe188d091274b5ffc8b3657bd85c63e969daa68ccb77afb05b071a4b62841acb7a21e417b5539014dff2ebf9550f0b14a9ff126f2734a7c1387f8e19
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -715,6 +715,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iconv-lite@npm:0.7.0":
|
||||
version: 0.7.0
|
||||
resolution: "iconv-lite@npm:0.7.0"
|
||||
dependencies:
|
||||
safer-buffer: "npm:>= 2.1.2 < 3.0.0"
|
||||
checksum: 10c0/2382400469071c55b6746c531eed5fa4d033e5db6690b7331fb2a5f59a30d7a9782932e92253db26df33c1cf46fa200a3fbe524a2a7c62037c762283f188ec2f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iconv-lite@npm:^0.6.2":
|
||||
version: 0.6.3
|
||||
resolution: "iconv-lite@npm:0.6.3"
|
||||
@@ -724,15 +733,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iconv-lite@npm:~0.7.0":
|
||||
version: 0.7.0
|
||||
resolution: "iconv-lite@npm:0.7.0"
|
||||
dependencies:
|
||||
safer-buffer: "npm:>= 2.1.2 < 3.0.0"
|
||||
checksum: 10c0/2382400469071c55b6746c531eed5fa4d033e5db6690b7331fb2a5f59a30d7a9782932e92253db26df33c1cf46fa200a3fbe524a2a7c62037c762283f188ec2f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ieee754@npm:^1.2.1":
|
||||
version: 1.2.1
|
||||
resolution: "ieee754@npm:1.2.1"
|
||||
@@ -754,16 +754,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"inherits@npm:~2.0.3, inherits@npm:~2.0.4":
|
||||
"inherits@npm:2.0.4, inherits@npm:~2.0.3":
|
||||
version: 2.0.4
|
||||
resolution: "inherits@npm:2.0.4"
|
||||
checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ioredis@npm:^5.8.2":
|
||||
version: 5.8.2
|
||||
resolution: "ioredis@npm:5.8.2"
|
||||
"ioredis@npm:^5.8.1":
|
||||
version: 5.8.1
|
||||
resolution: "ioredis@npm:5.8.1"
|
||||
dependencies:
|
||||
"@ioredis/commands": "npm:1.4.0"
|
||||
cluster-key-slot: "npm:^1.1.0"
|
||||
@@ -774,7 +774,7 @@ __metadata:
|
||||
redis-errors: "npm:^1.2.0"
|
||||
redis-parser: "npm:^3.0.0"
|
||||
standard-as-callback: "npm:^2.1.0"
|
||||
checksum: 10c0/305e385f811d49908899e32c2de69616cd059f909afd9e0a53e54f596b1a5835ee3449bfc6a3c49afbc5a2fd27990059e316cc78f449c94024957bd34c826d88
|
||||
checksum: 10c0/4ed66444017150da027bce940a24bf726994691e2a7b3aa11d52f8aeb37f258068cc171af4d9c61247acafc28eb086fa8a7c79420b8e8d2907d2f74f39584465
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1105,27 +1105,27 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"playwright-core@npm:1.57.0":
|
||||
version: 1.57.0
|
||||
resolution: "playwright-core@npm:1.57.0"
|
||||
"playwright-core@npm:1.55.1":
|
||||
version: 1.55.1
|
||||
resolution: "playwright-core@npm:1.55.1"
|
||||
bin:
|
||||
playwright-core: cli.js
|
||||
checksum: 10c0/798e35d83bf48419a8c73de20bb94d68be5dde68de23f95d80a0ebe401e3b83e29e3e84aea7894d67fa6c79d2d3d40cc5bcde3e166f657ce50987aaa2421b6a9
|
||||
checksum: 10c0/39837a8c1232ec27486eac8c3fcacc0b090acc64310f7f9004b06715370fc426f944e3610fe8c29f17cd3d68280ed72c75f660c02aa5b5cf0eb34bab0031308f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"playwright@npm:^1.57.0":
|
||||
version: 1.57.0
|
||||
resolution: "playwright@npm:1.57.0"
|
||||
"playwright@npm:^1.55.1":
|
||||
version: 1.55.1
|
||||
resolution: "playwright@npm:1.55.1"
|
||||
dependencies:
|
||||
fsevents: "npm:2.3.2"
|
||||
playwright-core: "npm:1.57.0"
|
||||
playwright-core: "npm:1.55.1"
|
||||
dependenciesMeta:
|
||||
fsevents:
|
||||
optional: true
|
||||
bin:
|
||||
playwright: cli.js
|
||||
checksum: 10c0/ab03c99a67b835bdea9059f516ad3b6e42c21025f9adaa161a4ef6bc7ca716dcba476d287140bb240d06126eb23f889a8933b8f5f1f1a56b80659d92d1358899
|
||||
checksum: 10c0/b84a97b0d764403df512f5bbb10c7343974e151a28202cc06f90883a13e8a45f4491a0597f0ae5fb03a026746cbc0d200f0f32195bfaa381aee5ca5770626771
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1160,15 +1160,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"raw-body@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "raw-body@npm:3.0.2"
|
||||
"raw-body@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "raw-body@npm:3.0.1"
|
||||
dependencies:
|
||||
bytes: "npm:~3.1.2"
|
||||
http-errors: "npm:~2.0.1"
|
||||
iconv-lite: "npm:~0.7.0"
|
||||
unpipe: "npm:~1.0.0"
|
||||
checksum: 10c0/d266678d08e1e7abea62c0ce5864344e980fa81c64f6b481e9842c5beaed2cdcf975f658a3ccd67ad35fc919c1f6664ccc106067801850286a6cbe101de89f29
|
||||
bytes: "npm:3.1.2"
|
||||
http-errors: "npm:2.0.0"
|
||||
iconv-lite: "npm:0.7.0"
|
||||
unpipe: "npm:1.0.0"
|
||||
checksum: 10c0/892f4fbd21ecab7e2fed0f045f7af9e16df7e8050879639d4e482784a2f4640aaaa33d916a0e98013f23acb82e09c2e3c57f84ab97104449f728d22f65a7d79a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1269,7 +1269,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"setprototypeof@npm:~1.2.0":
|
||||
"setprototypeof@npm:1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "setprototypeof@npm:1.2.0"
|
||||
checksum: 10c0/68733173026766fa0d9ecaeb07f0483f4c2dc70ca376b3b7c40b7cda909f94b0918f6c5ad5ce27a9160bdfb475efaa9d5e705a11d8eaae18f9835d20976028bc
|
||||
@@ -1367,10 +1367,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"statuses@npm:~2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "statuses@npm:2.0.2"
|
||||
checksum: 10c0/a9947d98ad60d01f6b26727570f3bcceb6c8fa789da64fe6889908fe2e294d57503b14bf2b5af7605c2d36647259e856635cd4c49eab41667658ec9d0080ec3f
|
||||
"statuses@npm:2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "statuses@npm:2.0.1"
|
||||
checksum: 10c0/34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1499,7 +1499,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"toidentifier@npm:~1.0.1":
|
||||
"toidentifier@npm:1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "toidentifier@npm:1.0.1"
|
||||
checksum: 10c0/93937279934bd66cc3270016dd8d0afec14fb7c94a05c72dc57321f8bd1fa97e5bea6d1f7c89e728d077ca31ea125b78320a616a6c6cd0e6b9cb94cb864381c1
|
||||
@@ -1531,7 +1531,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unpipe@npm:~1.0.0":
|
||||
"unpipe@npm:1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "unpipe@npm:1.0.0"
|
||||
checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
diff --git a/lib/zip-fs.js b/lib/zip-fs.js
|
||||
index 1444c0f00e5f1ad6c13521f90a7f3c6659d81116..90e38baef5365c2abbcb9337f7ab37f800e883a4 100644
|
||||
--- a/lib/zip-fs.js
|
||||
+++ b/lib/zip-fs.js
|
||||
@@ -33,12 +33,7 @@ import { initShimAsyncCodec } from "./core/util/stream-codec-shim.js";
|
||||
import { terminateWorkers } from "./core/codec-pool.js";
|
||||
|
||||
let baseURL;
|
||||
-try {
|
||||
- baseURL = import.meta.url;
|
||||
- // eslint-disable-next-line no-unused-vars
|
||||
-} catch (_) {
|
||||
- // ignored
|
||||
-}
|
||||
+
|
||||
configure({ baseURL });
|
||||
configureWebWorker(configure);
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
diff --git a/lib/zip-core-base.js b/lib/zip-core-base.js
|
||||
index 142155c8c3ab1a6caa7c370e8a2931a954556ca9..61b0fe6efb91312f437750e0002218f218afad8b 100644
|
||||
--- a/lib/zip-core-base.js
|
||||
+++ b/lib/zip-core-base.js
|
||||
@@ -28,12 +28,6 @@
|
||||
|
||||
import { configure } from "./core/configuration.js";
|
||||
|
||||
-try {
|
||||
- configure({ baseURI: import.meta.url });
|
||||
-} catch {
|
||||
- // ignored
|
||||
-}
|
||||
-
|
||||
export * from "./zip-core-reader.js";
|
||||
export * from "./zip-core-writer.js";
|
||||
export {
|
||||
@@ -8,11 +8,6 @@
|
||||
metosin/reitit-core {:mvn/version "0.9.1"}
|
||||
funcool/okulary {:mvn/version "2022.04.11-16"}
|
||||
|
||||
funcool/tubax
|
||||
{:git/tag "v2025.11.28"
|
||||
:git/sha "2d9a986"
|
||||
:git/url "https://github.com/funcool/tubax.git"}
|
||||
|
||||
funcool/potok2
|
||||
{:git/tag "v2.2"
|
||||
:git/sha "0f7e15a"
|
||||
@@ -25,8 +20,8 @@
|
||||
:git/url "https://github.com/funcool/beicon.git"}
|
||||
|
||||
funcool/rumext
|
||||
{:git/tag "v2.25"
|
||||
:git/sha "27e5a1a"
|
||||
{:git/tag "v2.24"
|
||||
:git/sha "17a0c94"
|
||||
:git/url "https://github.com/funcool/rumext.git"}
|
||||
|
||||
instaparse/instaparse {:mvn/version "1.5.0"}
|
||||
@@ -47,7 +42,7 @@
|
||||
:dev
|
||||
{:extra-paths ["dev"]
|
||||
:extra-deps
|
||||
{thheller/shadow-cljs {:mvn/version "3.2.2"}
|
||||
{thheller/shadow-cljs {:mvn/version "3.2.0"}
|
||||
com.bhauman/rebel-readline {:mvn/version "RELEASE"}
|
||||
org.clojure/tools.namespace {:mvn/version "RELEASE"}
|
||||
criterium/criterium {:mvn/version "RELEASE"}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"license": "MPL-2.0",
|
||||
"author": "Kaleidos INC",
|
||||
"private": true,
|
||||
"packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8",
|
||||
"packageManager": "yarn@4.10.3+sha512.c38cafb5c7bb273f3926d04e55e1d8c9dfa7d9c3ea1f36a4868fa028b9e5f72298f0b7f401ad5eb921749eb012eb1c3bb74bf7503df3ee43fd600d14a018266f",
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
@@ -14,10 +14,10 @@
|
||||
"url": "https://github.com/penpot/penpot"
|
||||
},
|
||||
"resolutions": {
|
||||
"@zip.js/zip.js@npm:^2.7.44": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch",
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"playwright": "1.52.0",
|
||||
"playwright-core": "1.52.0",
|
||||
"@zip.js/zip.js@npm:^2.7.44": "patch:@zip.js/zip.js@npm%3A2.8.11#~/.yarn/patches/@zip.js-zip.js-npm-2.8.11-b131c96df8.patch"
|
||||
"playwright-core": "1.52.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build:app:assets": "node ./scripts/build-app-assets.js",
|
||||
@@ -27,7 +27,6 @@
|
||||
"build:storybook:cljs": "clojure -M:dev:shadow-cljs compile storybook",
|
||||
"build:app:libs": "node ./scripts/build-libs.js",
|
||||
"build:app:main": "clojure -M:dev:shadow-cljs release main worker",
|
||||
"build:app:worker": "clojure -M:dev:shadow-cljs release worker",
|
||||
"build:app": "yarn run clear:shadow-cache && yarn run build:app:main && yarn run build:app:libs",
|
||||
"e2e:server": "node ./scripts/e2e-server.js",
|
||||
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
||||
@@ -53,74 +52,83 @@
|
||||
"watch:storybook:assets": "node ./scripts/watch-storybook.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@penpot/draft-js": "portal:./packages/draft-js",
|
||||
"@penpot/mousetrap": "portal:./packages/mousetrap",
|
||||
"@penpot/plugins-runtime": "1.3.2",
|
||||
"@penpot/svgo": "penpot/svgo#v3.1",
|
||||
"@penpot/text-editor": "portal:./text-editor",
|
||||
"@playwright/test": "1.57.0",
|
||||
"@storybook/addon-docs": "10.1.0",
|
||||
"@storybook/addon-themes": "10.1.0",
|
||||
"@storybook/addon-vitest": "10.1.0",
|
||||
"@storybook/react-vite": "10.1.0",
|
||||
"@tokens-studio/sd-transforms": "1.2.11",
|
||||
"@types/node": "^22.19.1",
|
||||
"@playwright/test": "1.52.0",
|
||||
"@storybook/addon-docs": "10.0.4",
|
||||
"@storybook/addon-themes": "10.0.4",
|
||||
"@storybook/addon-vitest": "10.0.4",
|
||||
"@storybook/react-vite": "10.0.4",
|
||||
"@types/node": "^22.15.21",
|
||||
"@vitest/browser": "3.2.4",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"@zip.js/zip.js": "patch:@zip.js/zip.js@npm%3A2.8.11#~/.yarn/patches/@zip.js-zip.js-npm-2.8.11-b131c96df8.patch",
|
||||
"autoprefixer": "^10.4.22",
|
||||
"compression": "^1.8.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"concurrently": "^9.2.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"esbuild": "^0.25.12",
|
||||
"eventsource-parser": "^3.0.6",
|
||||
"esbuild": "^0.25.9",
|
||||
"express": "^5.1.0",
|
||||
"fancy-log": "^2.0.0",
|
||||
"getopts": "^2.3.0",
|
||||
"gettext-parser": "^8.0.0",
|
||||
"highlight.js": "^11.10.0",
|
||||
"js-beautify": "^1.15.4",
|
||||
"jsdom": "^27.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-gzip": "^1.4.2",
|
||||
"gulp-mustache": "^5.0.0",
|
||||
"gulp-postcss": "^10.0.0",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"gulp-sourcemaps": "^3.0.0",
|
||||
"gulp-svg-sprite": "^2.0.3",
|
||||
"jsdom": "^27.0.0",
|
||||
"map-stream": "0.0.7",
|
||||
"marked": "^17.0.1",
|
||||
"marked": "^15.0.12",
|
||||
"mkdirp": "^3.0.1",
|
||||
"mustache": "^4.2.0",
|
||||
"nodemon": "^3.1.11",
|
||||
"nodemon": "^3.1.10",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"opentype.js": "^1.3.4",
|
||||
"p-limit": "^7.2.0",
|
||||
"playwright": "1.57.0",
|
||||
"postcss": "^8.5.6",
|
||||
"p-limit": "^6.2.0",
|
||||
"playwright": "1.56.1",
|
||||
"postcss": "^8.5.4",
|
||||
"postcss-clean": "^1.2.2",
|
||||
"postcss-modules": "^6.0.1",
|
||||
"prettier": "3.7.1",
|
||||
"prettier": "3.5.3",
|
||||
"pretty-time": "^1.1.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"randomcolor": "^0.6.2",
|
||||
"react": "19.2.0",
|
||||
"react-dom": "19.2.0",
|
||||
"react-error-boundary": "^6.0.0",
|
||||
"react-virtualized": "^9.22.6",
|
||||
"rimraf": "^6.1.2",
|
||||
"rxjs": "8.0.0-alpha.14",
|
||||
"rimraf": "^6.0.1",
|
||||
"sass": "^1.89.0",
|
||||
"sass-embedded": "^1.89.0",
|
||||
"sax": "^1.4.3",
|
||||
"source-map-support": "^0.5.21",
|
||||
"storybook": "10.1.0",
|
||||
"style-dictionary": "5.0.0-rc.1",
|
||||
"storybook": "10.0.4",
|
||||
"svg-sprite": "^2.0.4",
|
||||
"tdigest": "^0.1.2",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"typescript": "^5.9.3",
|
||||
"ua-parser-js": "2.0.6",
|
||||
"vite": "^6.4.1",
|
||||
"vitest": "^3.2.4",
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "^6.3.5",
|
||||
"vitest": "^3.2.0",
|
||||
"wasm-pack": "^0.13.1",
|
||||
"watcher": "^2.3.1",
|
||||
"workerpool": "^10.0.1",
|
||||
"workerpool": "^9.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@penpot/draft-js": "portal:./vendor/draft-js",
|
||||
"@penpot/hljs": "portal:./vendor/hljs",
|
||||
"@penpot/mousetrap": "portal:./vendor/mousetrap",
|
||||
"@penpot/plugins-runtime": "1.3.2",
|
||||
"@penpot/svgo": "penpot/svgo#v3.1",
|
||||
"@penpot/text-editor": "portal:./text-editor",
|
||||
"@tokens-studio/sd-transforms": "1.2.11",
|
||||
"@zip.js/zip.js": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch",
|
||||
"compression": "^1.8.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"eventsource-parser": "^3.0.6",
|
||||
"js-beautify": "^1.15.4",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"opentype.js": "^1.3.4",
|
||||
"postcss-modules": "^6.0.1",
|
||||
"randomcolor": "^0.6.2",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"react-error-boundary": "^6.0.0",
|
||||
"react-virtualized": "^9.22.6",
|
||||
"rxjs": "8.0.0-alpha.14",
|
||||
"sax": "^1.4.1",
|
||||
"source-map-support": "^0.5.21",
|
||||
"style-dictionary": "5.0.0-rc.1",
|
||||
"tdigest": "^0.1.2",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"ua-parser-js": "2.0.5",
|
||||
"xregexp": "^5.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
diff --git a/lib/zip-core-base.js b/lib/zip-core-base.js
|
||||
index 142155c8c3ab1a6caa7c370e8a2931a954556ca9..61b0fe6efb91312f437750e0002218f218afad8b 100644
|
||||
--- a/lib/zip-core-base.js
|
||||
+++ b/lib/zip-core-base.js
|
||||
@@ -28,12 +28,6 @@
|
||||
|
||||
import { configure } from "./core/configuration.js";
|
||||
|
||||
-try {
|
||||
- configure({ baseURI: import.meta.url });
|
||||
-} catch {
|
||||
- // ignored
|
||||
-}
|
||||
-
|
||||
export * from "./zip-core-reader.js";
|
||||
export * from "./zip-core-writer.js";
|
||||
export {
|
||||
@@ -22,9 +22,9 @@ export default defineConfig({
|
||||
workers: 1,
|
||||
/* Timeout for expects (longer in CI) */
|
||||
|
||||
timeout: 80000,
|
||||
timeout: 60000,
|
||||
expect: {
|
||||
timeout: process.env.CI ? 40000 : 5000,
|
||||
timeout: process.env.CI ? 30000 : 5000,
|
||||
},
|
||||
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -73,7 +73,7 @@ export class BasePage {
|
||||
}
|
||||
|
||||
static async mockConfigFlags(page, flags) {
|
||||
const url = "**/js/config.js";
|
||||
const url = "**/js/config.js?ts=*";
|
||||
return await page.route(url, (route) =>
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
|
||||
@@ -42,7 +42,7 @@ export class WasmWorkspacePage extends WorkspacePage {
|
||||
}
|
||||
|
||||
async waitForFirstRenderWithoutUI() {
|
||||
await this.waitForFirstRender();
|
||||
await waitForFirstRender();
|
||||
await this.hideUI();
|
||||
}
|
||||
|
||||
|
||||
@@ -258,22 +258,6 @@ test("Renders a file with nested frames with inherited blur", async ({
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("Renders a file with nested clipping frames", async ({ page }) => {
|
||||
const workspace = new WasmWorkspacePage(page);
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockGetFile(
|
||||
"render-wasm/get-file-frame-nested-clipping.json",
|
||||
);
|
||||
|
||||
await workspace.goToWorkspace({
|
||||
id: "44471494-966a-8178-8006-c5bd93f0fe72",
|
||||
pageId: "44471494-966a-8178-8006-c5bd93f0fe73",
|
||||
});
|
||||
await workspace.waitForFirstRenderWithoutUI();
|
||||
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("Renders a clipped frame with a large blur drop shadow", async ({
|
||||
page,
|
||||
}) => {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@@ -9,399 +9,403 @@ test.beforeEach(async ({ page }) => {
|
||||
]);
|
||||
});
|
||||
|
||||
test("Team with unlimited subscription has specific icon in menu", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
test.describe("Subscriptions: dashboard", () => {
|
||||
test("Team with unlimited subscription has specific icon in menu", async ({
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
await dashboardPage.goToSecondTeamDashboard();
|
||||
await expect(page.getByTestId("subscription-icon")).toBeVisible();
|
||||
});
|
||||
|
||||
test("The Unlimited subscription has its name in the sidebar dropdown", async ({
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
await dashboardPage.goToSecondTeamDashboard();
|
||||
await expect(page.getByTestId("subscription-icon")).toBeVisible();
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage-one-editor.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
await dashboardPage.goToDashboard();
|
||||
|
||||
await expect(page.getByTestId("subscription-name")).toHaveText(
|
||||
"Unlimited plan (trial)",
|
||||
);
|
||||
});
|
||||
|
||||
test("When the subscription status is unpaid, the sidebar dropdown displays the name Professional for the Unlimited subscription", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-unpaid-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
await dashboardPage.goToDashboard();
|
||||
|
||||
await expect(page.getByTestId("subscription-name")).toHaveText(
|
||||
"Professional plan",
|
||||
);
|
||||
});
|
||||
|
||||
test("When the subscription status is canceled, the sidebar dropdown displays the name Professional for the Enterprise subscription", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-enterprise-canceled-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
await dashboardPage.goToDashboard();
|
||||
|
||||
await expect(page.getByTestId("subscription-name")).toHaveText(
|
||||
"Professional plan",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("The Unlimited subscription has its name in the sidebar dropdown", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
test.describe("Subscriptions: team members and invitations", () => {
|
||||
test("Team settings has susbscription name and no manage subscription link when is member", async ({
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-member.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"subscription/get-team-members-subscription-member.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-stats?team-id=*",
|
||||
"dashboard/get-team-stats.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
|
||||
await dashboardPage.goToSecondTeamSettingsSection();
|
||||
await expect(page.getByText("Unlimited (trial)")).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("button", { name: "Manage your subscription" }),
|
||||
).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("Team settings has susbscription name and manage subscription link when is owner", async ({
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage-one-editor.json",
|
||||
);
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"subscription/get-team-members-subscription-owner.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-stats?team-id=*",
|
||||
"dashboard/get-team-stats.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
|
||||
await dashboardPage.goToSecondTeamSettingsSection();
|
||||
|
||||
await expect(page.getByText("Unlimited (trial)")).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("button", { name: "Manage your subscription" }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("Members tab has warning message when user has more seats than editors.", async ({
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"subscription/get-team-members-subscription-eight-member.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
|
||||
await dashboardPage.goToSecondTeamMembersSection();
|
||||
|
||||
const ctas = page.getByTestId("cta");
|
||||
await expect(ctas).toHaveCount(2);
|
||||
await expect(
|
||||
page.getByText("Inviting people while on the unlimited plan"),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("Invitations tab has warning message when user has more seats than editors.", async ({
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
await dashboardPage.goToDashboard();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await expect(page.getByTestId("subscription-name")).toHaveText(
|
||||
"Unlimited plan (trial)",
|
||||
);
|
||||
});
|
||||
|
||||
test("The sidebar dropdown displays the correct subscription name when status is Unpaid", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-unpaid-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
await dashboardPage.goToDashboard();
|
||||
|
||||
await expect(page.getByTestId("subscription-name")).toHaveText(
|
||||
"Professional plan",
|
||||
);
|
||||
});
|
||||
|
||||
test("The sidebar dropdown displays the correct subscription name when status is cancelled", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-enterprise-canceled-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
await dashboardPage.goToDashboard();
|
||||
|
||||
await expect(page.getByTestId("subscription-name")).toHaveText(
|
||||
"Professional plan",
|
||||
);
|
||||
});
|
||||
|
||||
test("Team settings has susbscription name and no manage subscription link when is member", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-member.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"subscription/get-team-members-subscription-member.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-stats?team-id=*",
|
||||
"dashboard/get-team-stats.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
|
||||
await dashboardPage.goToSecondTeamSettingsSection();
|
||||
await expect(page.getByText("Unlimited (trial)")).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("button", { name: "Manage your subscription" }),
|
||||
).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("Team settings has susbscription name and manage subscription link when is owner", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"subscription/get-team-members-subscription-owner.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-stats?team-id=*",
|
||||
"dashboard/get-team-stats.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
|
||||
await dashboardPage.goToSecondTeamSettingsSection();
|
||||
|
||||
await expect(page.getByText("Unlimited (trial)")).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("button", { name: "Manage your subscription" }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("Members tab has warning message when user has more seats than editors", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"subscription/get-team-members-subscription-eight-member.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
|
||||
await dashboardPage.goToSecondTeamMembersSection();
|
||||
|
||||
const ctas = page.getByTestId("cta");
|
||||
await expect(ctas).toHaveCount(2);
|
||||
await expect(
|
||||
page.getByText("Inviting people while on the unlimited plan"),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("Invitations tab has warning message when user has more seats than editors", async ({
|
||||
page,
|
||||
}) => {
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"subscription/get-profile-unlimited-subscription.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"subscription/get-team-members-subscription-eight-member.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-invitations?team-id=*",
|
||||
"subscription/get-team-invitations.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
|
||||
await dashboardPage.goToSecondTeamInvitationsSection();
|
||||
|
||||
const ctas = page.getByTestId("cta");
|
||||
await expect(ctas).toHaveCount(2);
|
||||
await expect(
|
||||
page.getByText("Inviting people while on the unlimited plan"),
|
||||
).toBeVisible();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-info",
|
||||
"subscription/get-team-info-subscriptions.json",
|
||||
);
|
||||
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"subscription/get-teams-unlimited-subscription-owner.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"dashboard/get-projects-second-team.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"subscription/get-team-members-subscription-eight-member.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-team-invitations?team-id=*",
|
||||
"subscription/get-team-invitations.json",
|
||||
);
|
||||
|
||||
await dashboardPage.mockRPC(
|
||||
"push-audit-events",
|
||||
"workspace/audit-event-empty.json",
|
||||
);
|
||||
|
||||
await dashboardPage.goToSecondTeamInvitationsSection();
|
||||
|
||||
const ctas = page.getByTestId("cta");
|
||||
await expect(ctas).toHaveCount(2);
|
||||
await expect(
|
||||
page.getByText("Inviting people while on the unlimited plan"),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -499,7 +499,7 @@ test.describe("Tokens: Tokens Tab", () => {
|
||||
await valueField.fill("");
|
||||
// TODO: We need to fix this translation
|
||||
await expect(
|
||||
tokensUpdateCreateModal.getByText("Token value cannot be empty"),
|
||||
tokensUpdateCreateModal.getByText("Empty field"),
|
||||
).toBeVisible();
|
||||
await valueSaturationSelector.click({ position: { x: 50, y: 50 } });
|
||||
await expect(valueField).toHaveValue(/^#[A-Fa-f\d]+$/);
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
patchedDependencies:
|
||||
'@zip.js/zip.js': patches/@zip.js__zip.js.patch
|
||||
|
||||
|
||||
shamefullyHoist: true
|
||||
recursiveInstall: true
|
||||
@@ -25,14 +25,14 @@
|
||||
<link rel="icon" href="images/favicon.png" />
|
||||
{{# manifest}}
|
||||
<script>window.penpotWorkerURI="{{& worker_main}}"</script>
|
||||
<script src="{{& config}}"></script>
|
||||
<script src="{{& polyfills}}"></script>
|
||||
<script defer src="{{& config}}"></script>
|
||||
<script defer src="{{& polyfills}}"></script>
|
||||
{{/manifest}}
|
||||
|
||||
<script type="module">
|
||||
globalThis.penpotTranslations = JSON.parse({{& translations}});
|
||||
globalThis.penpotVersion = "%version%";
|
||||
globalThis.penpotBuildDate = "%buildDate%";
|
||||
<script>
|
||||
window.penpotTranslations = JSON.parse({{& translations}});
|
||||
window.penpotVersion = "%version%";
|
||||
window.penpotBuildDate = "%buildDate%";
|
||||
</script>
|
||||
<!--cookie-consent-->
|
||||
</head>
|
||||
@@ -44,11 +44,9 @@
|
||||
<section id="modal"></section>
|
||||
|
||||
{{# manifest}}
|
||||
<script type="module" src="{{& libs}}"></script>
|
||||
<script type="module">
|
||||
import { init } from "{{& main}}";
|
||||
init();
|
||||
</script>
|
||||
<script defer src="js/libs.js?ts={{& ts}}"></script>
|
||||
<script defer src="{{& shared}}"></script>
|
||||
<script defer src="{{& main}}"></script>
|
||||
{{/manifest}}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -19,11 +19,9 @@
|
||||
</head>
|
||||
<body>
|
||||
{{# manifest}}
|
||||
<script type="module" src="{{& libs}}"></script>
|
||||
<script type="module">
|
||||
import { init } from "{{& rasterizer}}";
|
||||
init();
|
||||
</script>
|
||||
<script src="js/libs.js?ts={{& ts}}"></script>
|
||||
<script src="{{& shared}}"></script>
|
||||
<script src="{{& rasterizer}}"></script>
|
||||
{{/manifest}}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -18,11 +18,9 @@
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
{{# manifest}}
|
||||
<script type="module" src="{{& libs}}"></script>
|
||||
<script type="module">
|
||||
import { init } from "{{& render}}";
|
||||
init();
|
||||
</script>
|
||||
<script src="js/libs.js?ts={{& ts}}"></script>
|
||||
<script src="{{& shared}}"></script>
|
||||
<script src="{{& render}}"></script>
|
||||
{{/manifest}}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -193,30 +193,26 @@ async function readShadowManifest() {
|
||||
|
||||
const index = {
|
||||
ts: ts,
|
||||
config: "./js/config.js",
|
||||
polyfills: "./js/polyfills.js",
|
||||
worker_main: "./js/worker/main.js",
|
||||
libs: "./js/libs.js",
|
||||
config: "js/config.js?ts=" + ts,
|
||||
polyfills: "js/polyfills.js?ts=" + ts,
|
||||
worker_main: "js/worker/main.js?ts=" + ts,
|
||||
};
|
||||
|
||||
for (let item of content) {
|
||||
index[item.name] = "./js/" + item["output-name"] + "";
|
||||
index[item.name] = "js/" + item["output-name"];
|
||||
}
|
||||
|
||||
return index;
|
||||
} catch (cause) {
|
||||
const index = {
|
||||
return {
|
||||
ts: ts,
|
||||
config: "./js/config.js",
|
||||
polyfills: "./js/polyfills.js",
|
||||
main: "./js/main.js",
|
||||
shared: "./js/shared.js",
|
||||
worker_main: "./js/worker/main.js",
|
||||
rasterizer: "./js/rasterizer.js",
|
||||
libs: "./js/libs.js",
|
||||
config: "js/config.js?ts=" + ts,
|
||||
polyfills: "js/polyfills.js?ts=" + ts,
|
||||
main: "js/main.js?ts=" + ts,
|
||||
shared: "js/shared.js?ts=" + ts,
|
||||
worker_main: "js/worker/main.js?ts=" + ts,
|
||||
rasterizer: "js/rasterizer.js?ts=" + ts,
|
||||
};
|
||||
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,7 @@ yarn install || exit 1;
|
||||
rm -rf resources/public;
|
||||
rm -rf target/dist;
|
||||
|
||||
mkdir -p resources/public;
|
||||
mkdir -p target/dist;
|
||||
|
||||
yarn run build:app:main $EXTRA_PARAMS || exit 1
|
||||
yarn run build:app:main --config-merge "{:release-version \"${CURRENT_HASH}-${TS}\"}" $EXTRA_PARAMS || exit 1
|
||||
|
||||
if [ "$INCLUDE_WASM" = "yes" ]; then
|
||||
yarn run build:wasm || exit 1;
|
||||
@@ -38,18 +35,19 @@ fi
|
||||
yarn run build:app:libs || exit 1;
|
||||
yarn run build:app:assets || exit 1;
|
||||
|
||||
sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./resources/public/index.html;
|
||||
sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./resources/public/render.html;
|
||||
sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./resources/public/rasterizer.html;
|
||||
sed -i -re "s/\%buildDate\%/$BUILD_DATE/g" ./resources/public/index.html;
|
||||
sed -i -re "s/\%buildDate\%/$BUILD_DATE/g" ./resources/public/rasterizer.html;
|
||||
mkdir -p target/dist;
|
||||
rsync -avr resources/public/ target/dist/
|
||||
|
||||
sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./target/dist/index.html;
|
||||
sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./target/dist/render.html;
|
||||
sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./target/dist/rasterizer.html;
|
||||
sed -i -re "s/\%buildDate\%/$BUILD_DATE/g" ./target/dist/index.html;
|
||||
sed -i -re "s/\%buildDate\%/$BUILD_DATE/g" ./target/dist/rasterizer.html;
|
||||
|
||||
if [ "$INCLUDE_WASM" = "yes" ]; then
|
||||
sed -i "s/version=develop/version=$CURRENT_VERSION/g" ./resources/public/js/render_wasm.js;
|
||||
sed -i "s/version=develop/version=$CURRENT_VERSION/g" ./target/dist/js/render_wasm.js;
|
||||
fi
|
||||
|
||||
rsync -avr resources/public/ target/dist/;
|
||||
|
||||
if [ "$INCLUDE_STORYBOOK" = "yes" ]; then
|
||||
# build storybook
|
||||
yarn run build:storybook || exit 1;
|
||||
|
||||
@@ -31,9 +31,9 @@ const rebuildNotify = {
|
||||
const config = {
|
||||
entryPoints: ["target/index.js"],
|
||||
bundle: true,
|
||||
format: "esm",
|
||||
format: "iife",
|
||||
banner: {
|
||||
js: '"use strict";\nvar global = globalThis;',
|
||||
js: '"use strict"; var global = globalThis;',
|
||||
},
|
||||
outfile: "resources/public/js/libs.js",
|
||||
plugins: [fixReactVirtualized, rebuildNotify],
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
|
||||
yarn run lint:scss;
|
||||
yarn run test;
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
|
||||
yarn run playwright install chromium --with-deps;
|
||||
yarn run build:storybook
|
||||
|
||||
exec npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
|
||||
"npx http-server storybook-static --port 6006 --silent" \
|
||||
"npx wait-on tcp:6006 && yarn test:storybook"
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
corepack enable;
|
||||
corepack install;
|
||||
yarn install;
|
||||
yarn run playwright install chromium --with-deps;
|
||||
yarn run test:e2e -x --workers=2 --reporter=list "$@";
|
||||
@@ -6,12 +6,13 @@
|
||||
|
||||
:builds
|
||||
{:main
|
||||
{:target :esm
|
||||
{:target :browser
|
||||
:output-dir "resources/public/js/"
|
||||
:asset-path "/js"
|
||||
:devtools {:watch-dir "resources/public"
|
||||
:reload-strategy :full}
|
||||
:build-options {:manifest-name "manifest.json"}
|
||||
:module-loader true
|
||||
:modules
|
||||
{:shared
|
||||
{:entries []}
|
||||
@@ -19,7 +20,7 @@
|
||||
:main
|
||||
{:entries [app.main app.plugins.api]
|
||||
:depends-on #{:shared}
|
||||
:exports {init app.main/init}}
|
||||
:init-fn app.main/init}
|
||||
|
||||
:util-highlight
|
||||
{:entries [app.util.code-highlight]
|
||||
@@ -49,12 +50,12 @@
|
||||
:render
|
||||
{:entries [app.render]
|
||||
:depends-on #{:shared}
|
||||
:exports {init app.render/init}}
|
||||
:init-fn app.render/init}
|
||||
|
||||
:rasterizer
|
||||
{:entries [app.rasterizer]
|
||||
:depends-on #{:shared}
|
||||
:exports {init app.rasterizer/init}}}
|
||||
:init-fn app.rasterizer/init}}
|
||||
|
||||
:js-options
|
||||
{:entry-keys ["module" "browser" "main"]
|
||||
@@ -74,10 +75,11 @@
|
||||
:compiler-options
|
||||
{:fn-invoke-direct true
|
||||
:optimizations #shadow/env ["PENPOT_BUILD_OPTIMIZATIONS" :as :keyword :default :advanced]
|
||||
:output-wrapper true
|
||||
:rename-prefix-namespace "PENPOT"
|
||||
:source-map true
|
||||
:elide-asserts true
|
||||
:anon-fn-naming-policy :off
|
||||
:cross-chunk-method-motion false
|
||||
:source-map-detail-level :all}}}
|
||||
|
||||
:worker
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.profile :refer [schema:profile]]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
@@ -483,7 +484,7 @@
|
||||
|
||||
(defn delete-access-token
|
||||
[{:keys [id] :as params}]
|
||||
(assert (uuid? id))
|
||||
(us/assert! ::us/uuid id)
|
||||
(ptk/reify ::delete-access-token
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
|
||||
@@ -31,28 +31,27 @@
|
||||
[app.main.ui.static :as static]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.modules :as mod]
|
||||
[app.util.theme :as theme]
|
||||
[beicon.v2.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def auth-page
|
||||
(mf/lazy #(mod/load 'app.main.ui.auth/auth-page*)))
|
||||
(mf/lazy-component app.main.ui.auth/auth))
|
||||
|
||||
(def verify-token-page*
|
||||
(mf/lazy #(mod/load 'app.main.ui.auth.verify-token/verify-token-page*)))
|
||||
(def verify-token-page
|
||||
(mf/lazy-component app.main.ui.auth.verify-token/verify-token))
|
||||
|
||||
(def viewer-page*
|
||||
(mf/lazy #(mod/load 'app.main.ui.viewer/viewer-page*)))
|
||||
(mf/lazy-component app.main.ui.viewer/viewer*))
|
||||
|
||||
(def dashboard-page*
|
||||
(mf/lazy #(mod/load 'app.main.ui.dashboard/dashboard-page*)))
|
||||
(mf/lazy-component app.main.ui.dashboard/dashboard*))
|
||||
|
||||
(def settings-page*
|
||||
(mf/lazy #(mod/load 'app.main.ui.settings/settings-page*)))
|
||||
(mf/lazy-component app.main.ui.settings/settings*))
|
||||
|
||||
(def workspace-page*
|
||||
(mf/lazy #(mod/load 'app.main.ui.workspace/workspace-page*)))
|
||||
(mf/lazy-component app.main.ui.workspace/workspace*))
|
||||
|
||||
(mf/defc workspace-legacy-redirect*
|
||||
{::mf/props :obj
|
||||
@@ -190,7 +189,7 @@
|
||||
[:? [:& auth-page {:route route}]]
|
||||
|
||||
:auth-verify-token
|
||||
[:? [:& verify-token-page* {:route route}]]
|
||||
[:? [:& verify-token-page {:route route}]]
|
||||
|
||||
(:settings-profile
|
||||
:settings-password
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc auth*
|
||||
(mf/defc auth
|
||||
{::mf/props :obj}
|
||||
[{:keys [route]}]
|
||||
(let [section (dm/get-in route [:data :name])
|
||||
is-register (or
|
||||
@@ -68,9 +69,3 @@
|
||||
|
||||
(when (= section :auth-register)
|
||||
[:& terms-register])]]))
|
||||
|
||||
|
||||
(mf/defc auth-page*
|
||||
{::mf/lazy-load true}
|
||||
[props]
|
||||
[:> auth* props])
|
||||
|
||||
@@ -61,9 +61,9 @@
|
||||
(rt/nav :auth-login)
|
||||
(ntf/warn (tr "errors.unexpected-token"))))
|
||||
|
||||
(mf/defc verify-token*
|
||||
[{:keys [route]}]
|
||||
(let [token (get-in route [:query-params :token])
|
||||
(mf/defc verify-token
|
||||
[{:keys [route] :as props}]
|
||||
(let [token (get-in route [:query-params :token])
|
||||
bad-token (mf/use-state false)]
|
||||
|
||||
(mf/with-effect []
|
||||
@@ -99,8 +99,3 @@
|
||||
[:> static/invalid-token {}]
|
||||
[:> loader* {:title (tr "labels.loading")
|
||||
:overlay true}])))
|
||||
|
||||
(mf/defc verify-token-page*
|
||||
{::mf/lazy-load true}
|
||||
[props]
|
||||
[:> verify-token* props])
|
||||
|
||||
@@ -8,28 +8,24 @@
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.util.modules :as modules]
|
||||
[cuerdas.core :as str]
|
||||
[promesa.core :as p]
|
||||
[rumext.v2 :as mf]))
|
||||
[rumext.v2 :as mf]
|
||||
[shadow.lazy :as lazy]))
|
||||
|
||||
(def highlight-fn
|
||||
(delay (modules/load-fn 'app.util.code-highlight/highlight!)))
|
||||
(lazy/loadable app.util.code-highlight/highlight!))
|
||||
|
||||
(mf/defc code-block
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [code type]}]
|
||||
(let [block-ref (mf/use-ref)
|
||||
code (str/trim code)]
|
||||
code (str/trim code)]
|
||||
|
||||
(mf/with-effect [code type]
|
||||
(when-let [node (mf/ref-val block-ref)]
|
||||
(->> @highlight-fn
|
||||
(p/fmap (fn [f] (f)))
|
||||
(p/fnly (fn [f cause]
|
||||
(if cause
|
||||
(js/console.error cause)
|
||||
(f node)))))))
|
||||
(p/let [highlight-fn (lazy/load highlight-fn)]
|
||||
(highlight-fn node))))
|
||||
|
||||
[:pre {:class (dm/str type " " (stl/css :code-display)) :ref block-ref} code]))
|
||||
|
||||
|
||||
@@ -247,6 +247,7 @@
|
||||
(swap! storage/session dissoc :template))))))
|
||||
|
||||
(mf/defc dashboard*
|
||||
{::mf/props :obj}
|
||||
[{:keys [profile project-id team-id search-term plugin-url template section]}]
|
||||
(let [team (mf/deref refs/team)
|
||||
projects (mf/deref refs/projects)
|
||||
@@ -312,8 +313,3 @@
|
||||
:section section
|
||||
:search-term search-term
|
||||
:team team}]]]))
|
||||
|
||||
(mf/defc dashboard-page*
|
||||
{::mf/lazy-load true}
|
||||
[props]
|
||||
[:> dashboard* props])
|
||||
|
||||
@@ -78,9 +78,3 @@
|
||||
|
||||
:settings-notifications
|
||||
[:& notifications-page* {:profile profile}])]]]]))
|
||||
|
||||
(mf/defc settings-page*
|
||||
{::mf/lazy-load true}
|
||||
[props]
|
||||
[:> settings* props])
|
||||
|
||||
|
||||
@@ -624,6 +624,7 @@
|
||||
;; --- Component: Viewer
|
||||
|
||||
(mf/defc viewer*
|
||||
{::mf/props :obj}
|
||||
[{:keys [file-id share-id page-id] :as props}]
|
||||
(mf/with-effect [file-id page-id share-id]
|
||||
(let [params {:file-id file-id
|
||||
@@ -642,8 +643,3 @@
|
||||
[:> loader* {:title (tr "labels.loading")
|
||||
:overlay true}]))
|
||||
|
||||
|
||||
(mf/defc viewer-page*
|
||||
{::mf/lazy-load true}
|
||||
[props]
|
||||
[:> viewer* props])
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
(dsh/lookup-page state file-id page-id))))
|
||||
st/state))
|
||||
|
||||
(mf/defc workspace-inner*
|
||||
(mf/defc workspace-page*
|
||||
{::mf/private true}
|
||||
[{:keys [page-id file-id file layout wglobal]}]
|
||||
(let [page-ref (mf/with-memo [file-id page-id]
|
||||
@@ -252,16 +252,10 @@
|
||||
:touch-action "none"}}
|
||||
[:> context-menu*]
|
||||
(if (and file-loaded? page-id)
|
||||
[:> workspace-inner*
|
||||
[:> workspace-page*
|
||||
{:page-id page-id
|
||||
:file-id file-id
|
||||
:file file
|
||||
:wglobal wglobal
|
||||
:layout layout}]
|
||||
[:> workspace-loader*])]]]]]]))
|
||||
|
||||
(mf/defc workspace-page*
|
||||
{::mf/lazy-load true}
|
||||
[props]
|
||||
[:> workspace* props])
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
(ns app.main.ui.workspace.shapes.text.editor
|
||||
(:require
|
||||
["@penpot/draft-js" :as draft]
|
||||
["draft-js" :as draft]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
[app.util.object :as obj]
|
||||
[app.util.text.content :as content]
|
||||
[app.util.text.content.styles :as styles]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn get-contrast-color [background-color]
|
||||
@@ -269,12 +268,7 @@
|
||||
"bottom" "flex-end"
|
||||
nil))
|
||||
|
||||
(defn- font-family-from-font-id [font-id]
|
||||
(if (str/includes? font-id "gfont-noto-sans")
|
||||
(let [lang (str/replace font-id #"gfont\-noto\-sans\-" "")]
|
||||
(if (>= (count lang) 3) (str/capital lang) (str/upper lang)))
|
||||
"Noto Color Emoji"))
|
||||
|
||||
;;
|
||||
;; Text Editor Wrapper
|
||||
;; This is an SVG element that wraps the HTML editor.
|
||||
;;
|
||||
@@ -287,10 +281,6 @@
|
||||
(let [shape-id (dm/get-prop shape :id)
|
||||
modifiers (dm/get-in modifiers [shape-id :modifiers])
|
||||
|
||||
fallback-fonts (wasm.api/fonts-from-text-content (:content shape) false)
|
||||
fallback-families (map (fn [font]
|
||||
(font-family-from-font-id (:font-id font))) fallback-fonts)
|
||||
|
||||
clip-id (dm/str "text-edition-clip" shape-id)
|
||||
|
||||
text-modifier-ref
|
||||
@@ -327,7 +317,7 @@
|
||||
max-height (max height selrect-height)
|
||||
valign (-> shape :content :vertical-align)
|
||||
y (:y selrect)
|
||||
y (if (and valign (> height selrect-height))
|
||||
y (if (> height selrect-height)
|
||||
(case valign
|
||||
"bottom" (- y (- height selrect-height))
|
||||
"center" (- y (/ (- height selrect-height) 2))
|
||||
@@ -351,8 +341,7 @@
|
||||
render-wasm?
|
||||
(obj/merge!
|
||||
#js {"--editor-container-width" (dm/str width "px")
|
||||
"--editor-container-height" (dm/str height "px")
|
||||
"--fallback-families" (dm/str (str/join ", " fallback-families))})
|
||||
"--editor-container-height" (dm/str height "px")})
|
||||
|
||||
(not render-wasm?)
|
||||
(obj/merge!
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.path-names :as cpn]
|
||||
[app.common.spec :as us]
|
||||
[app.common.thumbnails :as thc]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.types.container :as ctn]
|
||||
@@ -37,6 +38,7 @@
|
||||
[app.util.i18n :as i18n :refer [c tr]]
|
||||
[app.util.strings :refer [matches-search]]
|
||||
[app.util.timers :as ts]
|
||||
[cljs.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
@@ -95,6 +97,10 @@
|
||||
(str (str/slice (:path asset) (count path)))
|
||||
(cpn/merge-path-item (:name asset))))
|
||||
|
||||
(s/def ::asset-name ::us/not-empty-string)
|
||||
(s/def ::name-group-form
|
||||
(s/keys :req-un [::asset-name]))
|
||||
|
||||
(def initial-context-menu-state
|
||||
{:open? false :top nil :left nil})
|
||||
|
||||
|
||||
@@ -38,18 +38,30 @@
|
||||
(features/use-feature "render-wasm/v1")
|
||||
|
||||
has-invalid-shapes?
|
||||
(some (if render-wasm-enabled?
|
||||
cfh/frame-shape?
|
||||
#(or (cfh/frame-shape? %) (cfh/text-shape? %)))
|
||||
shapes-with-children)
|
||||
(if render-wasm-enabled?
|
||||
false
|
||||
(some (fn [shape]
|
||||
(or (cfh/frame-shape? shape)
|
||||
(cfh/text-shape? shape)))
|
||||
shapes-with-children))
|
||||
|
||||
head-not-group-like?
|
||||
(and (= 1 total-selected)
|
||||
(not is-group?)
|
||||
(not is-bool?))
|
||||
|
||||
disabled-bool-btns (or (zero? total-selected) has-invalid-shapes? head-not-group-like?)
|
||||
disabled-flatten (or (zero? total-selected) has-invalid-shapes?)
|
||||
disabled-bool-btns
|
||||
(if render-wasm-enabled?
|
||||
false
|
||||
(or (zero? total-selected)
|
||||
has-invalid-shapes?
|
||||
head-not-group-like?))
|
||||
|
||||
disabled-flatten
|
||||
(if render-wasm-enabled?
|
||||
false
|
||||
(or (zero? total-selected)
|
||||
has-invalid-shapes?))
|
||||
|
||||
on-change
|
||||
(mf/use-fn
|
||||
|
||||
@@ -32,12 +32,6 @@
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn- token-value-error-fn
|
||||
[{:keys [value]}]
|
||||
(when (or (str/empty? value)
|
||||
(str/blank? value))
|
||||
(tr "workspace.tokens.empty-input")))
|
||||
|
||||
(defn- make-schema
|
||||
[tokens-tree]
|
||||
(sm/schema
|
||||
@@ -50,7 +44,7 @@
|
||||
[:fn {:error/fn #(tr "workspace.tokens.token-name-duplication-validation-error" (:value %))}
|
||||
#(not (cft/token-name-path-exists? % tokens-tree))]]]
|
||||
|
||||
[:value [::sm/text {:error/fn token-value-error-fn}]]
|
||||
[:value ::sm/text]
|
||||
|
||||
[:resolved-value ::sm/any]
|
||||
|
||||
|
||||
@@ -32,12 +32,6 @@
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn- token-value-error-fn
|
||||
[{:keys [value]}]
|
||||
(when (or (str/empty? value)
|
||||
(str/blank? value))
|
||||
(tr "workspace.tokens.empty-input")))
|
||||
|
||||
(defn- make-schema
|
||||
[tokens-tree]
|
||||
(sm/schema
|
||||
@@ -50,7 +44,7 @@
|
||||
[:fn {:error/fn #(tr "workspace.tokens.token-name-duplication-validation-error" (:value %))}
|
||||
#(not (cft/token-name-path-exists? % tokens-tree))]]]
|
||||
|
||||
[:value [::sm/text {:error/fn token-value-error-fn}]]
|
||||
[:value ::sm/text]
|
||||
|
||||
[:resolved-value ::sm/any]
|
||||
|
||||
|
||||
@@ -32,12 +32,6 @@
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn- token-value-error-fn
|
||||
[{:keys [value]}]
|
||||
(when (or (str/empty? value)
|
||||
(str/blank? value))
|
||||
(tr "workspace.tokens.empty-input")))
|
||||
|
||||
(defn- make-schema
|
||||
[tokens-tree]
|
||||
(sm/schema
|
||||
@@ -50,7 +44,7 @@
|
||||
[:fn {:error/fn #(tr "workspace.tokens.token-name-duplication-validation-error" (:value %))}
|
||||
#(not (cft/token-name-path-exists? % tokens-tree))]]]
|
||||
|
||||
[:value [::sm/text {:error/fn token-value-error-fn}]]
|
||||
[:value ::sm/text]
|
||||
|
||||
[:resolved-value ::sm/any]
|
||||
|
||||
|
||||
@@ -205,7 +205,6 @@
|
||||
;; TODO: Review this value vs default-value
|
||||
:value (or value "")
|
||||
:hint-message (:message hint)
|
||||
:variant "comfortable"
|
||||
:slot-start swatch
|
||||
:hint-type (:type hint)})
|
||||
|
||||
|
||||
@@ -83,7 +83,6 @@
|
||||
(mf/spread-props props {:on-change on-change
|
||||
:default-value value
|
||||
:hint-message (:message hint)
|
||||
:variant "comfortable"
|
||||
:hint-type (:type hint)})
|
||||
|
||||
props
|
||||
|
||||
@@ -32,12 +32,6 @@
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn- token-value-error-fn
|
||||
[{:keys [value]}]
|
||||
(when (or (str/empty? value)
|
||||
(str/blank? value))
|
||||
(tr "workspace.tokens.empty-input")))
|
||||
|
||||
(defn- make-schema
|
||||
[tokens-tree]
|
||||
(sm/schema
|
||||
@@ -50,7 +44,7 @@
|
||||
[:fn {:error/fn #(tr "workspace.tokens.token-name-duplication-validation-error" (:value %))}
|
||||
#(not (cft/token-name-path-exists? % tokens-tree))]]]
|
||||
|
||||
[:value [::sm/text {:error/fn token-value-error-fn}]]
|
||||
[:value ::sm/text]
|
||||
|
||||
[:resolved-value ::sm/any]
|
||||
|
||||
|
||||
@@ -216,6 +216,18 @@
|
||||
on-frame-leave (actions/on-frame-leave frame-hover)
|
||||
on-frame-select (actions/on-frame-select selected read-only?)
|
||||
|
||||
;; Text Editor Event Handlers
|
||||
on-text-keydown (fn [event]
|
||||
(when (and text-editing? (.-key event))
|
||||
(.preventDefault event)
|
||||
(wasm.api/handle-text-keydown (.-key event))))
|
||||
on-text-mousedown (fn [event]
|
||||
(when text-editing?
|
||||
(let [rect (.getBoundingClientRect (.-currentTarget event))
|
||||
x (- (.-clientX event) (.-left rect))
|
||||
y (- (.-clientY event) (.-top rect))]
|
||||
(wasm.api/handle-text-mousedown x y))))
|
||||
|
||||
disable-events? (contains? layout :comments)
|
||||
show-comments? (= drawing-tool :comments)
|
||||
show-cursor-tooltip? tooltip
|
||||
@@ -231,8 +243,9 @@
|
||||
|
||||
show-pixel-grid? (and (contains? layout :show-pixel-grid)
|
||||
(>= zoom 8))
|
||||
show-text-editor? (and editing-shape (= :text (:type editing-shape)))
|
||||
;; show-text-editor? (and editing-shape (= :text (:type editing-shape)))
|
||||
|
||||
show-text-editor? false
|
||||
hover-grid? (and (some? @hover-top-frame-id)
|
||||
(ctl/grid-layout? objects @hover-top-frame-id))
|
||||
|
||||
@@ -419,7 +432,9 @@
|
||||
:on-pointer-enter on-pointer-enter
|
||||
:on-pointer-leave on-pointer-leave
|
||||
:on-pointer-move on-pointer-move
|
||||
:on-pointer-up on-pointer-up}
|
||||
:on-pointer-up on-pointer-up
|
||||
:on-key-down on-text-keydown
|
||||
:on-mouse-down on-text-mousedown}
|
||||
|
||||
[:defs
|
||||
;; This clip is so the handlers are not over the rulers
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
(ns app.plugins.comments
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.spec :as us]
|
||||
[app.main.data.comments :as dc]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace.comments :as dwc]
|
||||
@@ -118,8 +118,7 @@
|
||||
(fn [position]
|
||||
(let [position (parser/parse-point position)]
|
||||
(cond
|
||||
(or (not (sm/valid-safe-number? (:x position)))
|
||||
(not (sm/valid-safe-number? (:y position))))
|
||||
(or (not (us/safe-number? (:x position))) (not (us/safe-number? (:y position))))
|
||||
(u/display-not-valid :position "Not valid point")
|
||||
|
||||
(not (r/check-permission plugin-id "comment:write"))
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
(ns app.plugins.flex
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.data.workspace.transforms :as dwt]
|
||||
@@ -133,7 +133,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :rowGap value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -148,7 +148,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :columnGap value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -163,7 +163,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :verticalPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -178,7 +178,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :horizontalPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -194,7 +194,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :topPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -209,7 +209,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :rightPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -224,7 +224,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :bottomPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -239,7 +239,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :leftPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -296,7 +296,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(sm/valid-safe-int? value)
|
||||
(us/safe-int? value)
|
||||
(u/display-not-valid :zIndex value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -359,7 +359,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :verticalMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -374,7 +374,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :horizontalMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -389,7 +389,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :topMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -404,7 +404,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :rightMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -419,7 +419,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :bottomMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -434,7 +434,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :leftMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -449,7 +449,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :maxWidth value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -464,7 +464,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :minWidth value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -479,7 +479,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :maxHeight value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -494,7 +494,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :minHeight value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
(ns app.plugins.grid
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.data.workspace.transforms :as dwt]
|
||||
@@ -126,7 +126,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :rowGap value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -141,7 +141,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :columnGap value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -156,7 +156,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :verticalPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -171,7 +171,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :horizontalPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -186,7 +186,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :topPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -201,7 +201,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :rightPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -216,7 +216,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :bottomPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -231,7 +231,7 @@
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :leftPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -248,7 +248,7 @@
|
||||
(u/display-not-valid :addRow-type type)
|
||||
|
||||
(and (or (= :percent type) (= :flex type) (= :fixed type))
|
||||
(not (sm/valid-safe-number? value)))
|
||||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :addRow-value value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -261,14 +261,14 @@
|
||||
(fn [index type value]
|
||||
(let [type (keyword type)]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? index))
|
||||
(not (us/safe-int? index))
|
||||
(u/display-not-valid :addRowAtIndex-index index)
|
||||
|
||||
(not (contains? ctl/grid-track-types type))
|
||||
(u/display-not-valid :addRowAtIndex-type type)
|
||||
|
||||
(and (or (= :percent type) (= :flex type) (= :fixed type))
|
||||
(not (sm/valid-safe-number? value)))
|
||||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :addRowAtIndex-value value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -285,7 +285,7 @@
|
||||
(u/display-not-valid :addColumn-type type)
|
||||
|
||||
(and (or (= :percent type) (= :flex type) (= :lex type))
|
||||
(not (sm/valid-safe-number? value)))
|
||||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :addColumn-value value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -297,14 +297,14 @@
|
||||
:addColumnAtIndex
|
||||
(fn [index type value]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? index))
|
||||
(not (us/safe-int? index))
|
||||
(u/display-not-valid :addColumnAtIndex-index index)
|
||||
|
||||
(not (contains? ctl/grid-track-types type))
|
||||
(u/display-not-valid :addColumnAtIndex-type type)
|
||||
|
||||
(and (or (= :percent type) (= :flex type) (= :fixed type))
|
||||
(not (sm/valid-safe-number? value)))
|
||||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :addColumnAtIndex-value value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -317,7 +317,7 @@
|
||||
:removeRow
|
||||
(fn [index]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? index))
|
||||
(not (us/safe-int? index))
|
||||
(u/display-not-valid :removeRow index)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -329,7 +329,7 @@
|
||||
:removeColumn
|
||||
(fn [index]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? index))
|
||||
(not (us/safe-int? index))
|
||||
(u/display-not-valid :removeColumn index)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -342,14 +342,14 @@
|
||||
(fn [index type value]
|
||||
(let [type (keyword type)]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? index))
|
||||
(not (us/safe-int? index))
|
||||
(u/display-not-valid :setColumn-index index)
|
||||
|
||||
(not (contains? ctl/grid-track-types type))
|
||||
(u/display-not-valid :setColumn-type type)
|
||||
|
||||
(and (or (= :percent type) (= :flex type) (= :fixed type))
|
||||
(not (sm/valid-safe-number? value)))
|
||||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :setColumn-value value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -362,14 +362,14 @@
|
||||
(fn [index type value]
|
||||
(let [type (keyword type)]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? index))
|
||||
(not (us/safe-int? index))
|
||||
(u/display-not-valid :setRow-index index)
|
||||
|
||||
(not (contains? ctl/grid-track-types type))
|
||||
(u/display-not-valid :setRow-type type)
|
||||
|
||||
(and (or (= :percent type) (= :flex type) (= :fixed type))
|
||||
(not (sm/valid-safe-number? value)))
|
||||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :setRow-value value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -393,10 +393,10 @@
|
||||
(not (shape-proxy? child))
|
||||
(u/display-not-valid :appendChild-child child)
|
||||
|
||||
(or (< row 0) (not (sm/valid-safe-int? row)))
|
||||
(or (< row 0) (not (us/safe-int? row)))
|
||||
(u/display-not-valid :appendChild-row row)
|
||||
|
||||
(or (< column 0) (not (sm/valid-safe-int? column)))
|
||||
(or (< column 0) (not (us/safe-int? column)))
|
||||
(u/display-not-valid :appendChild-column column)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -431,7 +431,7 @@
|
||||
(let [cell (locate-cell self)
|
||||
shape (u/proxy->shape self)]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :row-value value)
|
||||
|
||||
(nil? cell)
|
||||
@@ -451,7 +451,7 @@
|
||||
(let [shape (u/proxy->shape self)
|
||||
cell (locate-cell self)]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :rowSpan-value value)
|
||||
|
||||
(nil? cell)
|
||||
@@ -471,7 +471,7 @@
|
||||
(let [shape (u/proxy->shape self)
|
||||
cell (locate-cell self)]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :column-value value)
|
||||
|
||||
(nil? cell)
|
||||
@@ -491,7 +491,7 @@
|
||||
(let [shape (u/proxy->shape self)
|
||||
cell (locate-cell self)]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :columnSpan-value value)
|
||||
|
||||
(nil? cell)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.color :as cc]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.comments :as dc]
|
||||
@@ -299,7 +299,7 @@
|
||||
(fn [orientation value board]
|
||||
(let [shape (u/proxy->shape board)]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :addRulerGuide "Value not a safe number")
|
||||
|
||||
(not (contains? #{"vertical" "horizontal"} orientation))
|
||||
@@ -345,8 +345,8 @@
|
||||
(or (not (string? content)) (empty? content))
|
||||
(u/display-not-valid :addCommentThread "Content not valid")
|
||||
|
||||
(or (not (sm/valid-safe-number? (:x position)))
|
||||
(not (sm/valid-safe-number? (:y position))))
|
||||
(or (not (us/safe-number? (:x position)))
|
||||
(not (us/safe-number? (:y position))))
|
||||
(u/display-not-valid :addCommentThread "Position not valid")
|
||||
|
||||
(and (some? board) (or (not (shape/shape-proxy? board)) (not (cfh/frame-shape? shape))))
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.spec :as us]
|
||||
[app.main.data.workspace.guides :as dwgu]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.format :as format]
|
||||
@@ -77,7 +77,7 @@
|
||||
:set
|
||||
(fn [self value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :position "Not valid position")
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
[app.common.path-names :as cpn]
|
||||
[app.common.record :as crc]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.spec :as us]
|
||||
[app.common.svg.path :as svg.path]
|
||||
[app.common.types.color :as clr]
|
||||
[app.common.types.component :as ctk]
|
||||
@@ -324,7 +325,7 @@
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(or (not (sm/valid-safe-int? value)) (< value 0))
|
||||
(or (not (us/safe-int? value)) (< value 0))
|
||||
(u/display-not-valid :borderRadius value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -340,7 +341,7 @@
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :borderRadiusTopLeft value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -356,7 +357,7 @@
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :borderRadiusTopRight value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -372,7 +373,7 @@
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :borderRadiusBottomRight value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -388,7 +389,7 @@
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? value))
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :borderRadiusBottomLeft value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -404,7 +405,7 @@
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(or (not (sm/valid-safe-number? value)) (< value 0) (> value 1))
|
||||
(or (not (us/safe-number? value)) (< value 0) (> value 1))
|
||||
(u/display-not-valid :opacity value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -491,7 +492,7 @@
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :x value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -509,7 +510,7 @@
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :y value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -554,7 +555,7 @@
|
||||
:set
|
||||
(fn [self value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :parentX value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -581,7 +582,7 @@
|
||||
:set
|
||||
(fn [self value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :parentY value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -608,7 +609,7 @@
|
||||
:set
|
||||
(fn [self value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :frameX value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -635,7 +636,7 @@
|
||||
:set
|
||||
(fn [self value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :frameY value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -794,10 +795,10 @@
|
||||
:resize
|
||||
(fn [width height]
|
||||
(cond
|
||||
(or (not (sm/valid-safe-number? width)) (<= width 0))
|
||||
(or (not (us/safe-number? width)) (<= width 0))
|
||||
(u/display-not-valid :resize width)
|
||||
|
||||
(or (not (sm/valid-safe-number? height)) (<= height 0))
|
||||
(or (not (us/safe-number? height)) (<= height 0))
|
||||
(u/display-not-valid :resize height)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -1047,10 +1048,10 @@
|
||||
(not (cfh/text-shape? shape))
|
||||
(u/display-not-valid :getRange-shape "shape is not text")
|
||||
|
||||
(or (not (sm/valid-safe-int? start)) (< start 0) (> start end))
|
||||
(or (not (us/safe-int? start)) (< start 0) (> start end))
|
||||
(u/display-not-valid :getRange-start start)
|
||||
|
||||
(not (sm/valid-safe-int? end))
|
||||
(not (us/safe-int? end))
|
||||
(u/display-not-valid :getRange-end end)
|
||||
|
||||
:else
|
||||
@@ -1077,7 +1078,7 @@
|
||||
:setParentIndex
|
||||
(fn [index]
|
||||
(cond
|
||||
(not (sm/valid-safe-int? index))
|
||||
(not (us/safe-int? index))
|
||||
(u/display-not-valid :setParentIndex index)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
@@ -1229,7 +1230,7 @@
|
||||
(fn [orientation value]
|
||||
(let [shape (u/locate-shape file-id page-id id)]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :addRulerGuide "Value not a safe number")
|
||||
|
||||
(not (contains? #{"vertical" "horizontal"} orientation))
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
(ns app.plugins.viewport
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.spec :as us]
|
||||
[app.main.data.workspace.viewport :as dwv]
|
||||
[app.main.data.workspace.zoom :as dwz]
|
||||
[app.main.store :as st]
|
||||
@@ -37,10 +37,10 @@
|
||||
(let [new-x (obj/get value "x")
|
||||
new-y (obj/get value "y")]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? new-x))
|
||||
(not (us/safe-number? new-x))
|
||||
(u/display-not-valid :center-x new-x)
|
||||
|
||||
(not (sm/valid-safe-number? new-y))
|
||||
(not (us/safe-number? new-y))
|
||||
(u/display-not-valid :center-y new-y)
|
||||
|
||||
:else
|
||||
@@ -62,7 +62,7 @@
|
||||
:set
|
||||
(fn [value]
|
||||
(cond
|
||||
(not (sm/valid-safe-number? value))
|
||||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :zoom value)
|
||||
|
||||
:else
|
||||
|
||||
@@ -125,40 +125,47 @@
|
||||
[:embed {:optional true} :boolean]
|
||||
[:skip-children {:optional true} :boolean]
|
||||
[:object-id
|
||||
[:or [::sm/set ::sm/uuid] ::sm/uuid]]])
|
||||
[:or
|
||||
::sm/uuid
|
||||
::sm/coll-of-uuid]]])
|
||||
|
||||
(def ^:private coerce-render-objects-params
|
||||
(sm/coercer schema:render-objects))
|
||||
(def ^:private render-objects-decoder
|
||||
(sm/lazy-decoder schema:render-objects
|
||||
sm/string-transformer))
|
||||
|
||||
(def ^:private render-objects-validator
|
||||
(sm/lazy-validator schema:render-objects))
|
||||
|
||||
(defn- render-objects
|
||||
[params]
|
||||
(try
|
||||
(let [{:keys [file-id page-id embed share-id object-id skip-children] :as params}
|
||||
(coerce-render-objects-params params)]
|
||||
(st/emit! (fetch-objects-bundle :file-id file-id :page-id page-id :share-id share-id :object-id object-id))
|
||||
(if (uuid? object-id)
|
||||
(mf/html
|
||||
[:& object-svg
|
||||
{:file-id file-id
|
||||
:page-id page-id
|
||||
:share-id share-id
|
||||
:object-id object-id
|
||||
:embed embed
|
||||
:skip-children skip-children}])
|
||||
(let [{:keys [file-id page-id embed share-id object-id skip-children] :as params} (render-objects-decoder params)]
|
||||
(if-not (render-objects-validator params)
|
||||
(do
|
||||
(js/console.error "invalid arguments")
|
||||
(sm/pretty-explain schema:render-objects params)
|
||||
nil)
|
||||
|
||||
(mf/html
|
||||
[:& objects-svg
|
||||
{:file-id file-id
|
||||
:page-id page-id
|
||||
:share-id share-id
|
||||
:object-ids (into #{} object-id)
|
||||
:embed embed
|
||||
:skip-children skip-children}])))
|
||||
(catch :default cause
|
||||
(when-let [explain (-> cause ex-data ::sm/explain)]
|
||||
(js/console.log "Unexpected error")
|
||||
(js/console.log (sm/humanize-explain explain)))
|
||||
(mf/html [:span "Unexpected error:" (ex-message cause)]))))
|
||||
(do
|
||||
(st/emit! (fetch-objects-bundle :file-id file-id :page-id page-id :share-id share-id :object-id object-id))
|
||||
|
||||
(if (uuid? object-id)
|
||||
(mf/html
|
||||
[:& object-svg
|
||||
{:file-id file-id
|
||||
:page-id page-id
|
||||
:share-id share-id
|
||||
:object-id object-id
|
||||
:embed embed
|
||||
:skip-children skip-children}])
|
||||
|
||||
(mf/html
|
||||
[:& objects-svg
|
||||
{:file-id file-id
|
||||
:page-id page-id
|
||||
:share-id share-id
|
||||
:object-ids (into #{} object-id)
|
||||
:embed embed
|
||||
:skip-children skip-children}]))))))
|
||||
|
||||
;; ---- COMPONENTS SPRITE
|
||||
|
||||
@@ -235,37 +242,39 @@
|
||||
[:embed {:optional true} :boolean]
|
||||
[:component-id {:optional true} ::sm/uuid]])
|
||||
|
||||
(def ^:private coerce-render-components-params
|
||||
(sm/coercer schema:render-components))
|
||||
(def ^:private render-components-decoder
|
||||
(sm/lazy-decoder schema:render-components
|
||||
sm/string-transformer))
|
||||
|
||||
(def ^:private render-components-validator
|
||||
(sm/lazy-validator schema:render-components))
|
||||
|
||||
(defn render-components
|
||||
[params]
|
||||
(try
|
||||
(let [{:keys [file-id component-id embed] :as params}
|
||||
(coerce-render-components-params params)]
|
||||
(let [{:keys [file-id component-id embed] :as params} (render-components-decoder params)]
|
||||
(if-not (render-components-validator params)
|
||||
(do
|
||||
(js/console.error "invalid arguments")
|
||||
(sm/pretty-explain schema:render-components params)
|
||||
nil)
|
||||
|
||||
(st/emit! (ptk/reify ::initialize-render-components
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(rx/merge
|
||||
(rx/of (fetch-team :file-id file-id))
|
||||
(do
|
||||
(st/emit! (ptk/reify ::initialize-render-components
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(rx/merge
|
||||
(rx/of (fetch-team :file-id file-id))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::team-fetched))
|
||||
(rx/observe-on :async)
|
||||
(rx/map (constantly params))
|
||||
(rx/map fetch-components-bundle))))))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::team-fetched))
|
||||
(rx/observe-on :async)
|
||||
(rx/map (constantly params))
|
||||
(rx/map fetch-components-bundle))))))
|
||||
|
||||
(mf/html
|
||||
[:& components-svg
|
||||
{:component-id component-id
|
||||
:embed embed}]))
|
||||
|
||||
(catch :default cause
|
||||
(when-let [explain (-> cause ex-data ::sm/explain)]
|
||||
(js/console.log "Unexpected error")
|
||||
(js/console.log (sm/humanize-explain explain)))
|
||||
(mf/html [:span "Unexpected error:" (ex-message cause)]))))
|
||||
(mf/html
|
||||
[:& components-svg
|
||||
{:component-id component-id
|
||||
:embed embed}])))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SETUP
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
[app.util.debug :as dbg]
|
||||
[app.util.functions :as fns]
|
||||
[app.util.globals :as ug]
|
||||
[app.util.modules :as mod]
|
||||
[app.util.text.content :as tc]
|
||||
[beicon.v2.core :as rx]
|
||||
[promesa.core :as p]
|
||||
@@ -476,9 +475,9 @@
|
||||
(dissoc :style)
|
||||
(merge style)
|
||||
(select-keys allowed-keys))
|
||||
fill-rule (-> (or (:fill-rule attrs) (:fillRule attrs)) sr/translate-fill-rule)
|
||||
stroke-linecap (-> (or (:stroke-linecap attrs) (:strokeLinecap attrs)) sr/translate-stroke-linecap)
|
||||
stroke-linejoin (-> (or (:stroke-linejoin attrs) (:strokeLinejoin attrs)) sr/translate-stroke-linejoin)
|
||||
fill-rule (or (-> attrs :fill-rule sr/translate-fill-rule) (-> attrs :fillRule sr/translate-fill-rule))
|
||||
stroke-linecap (or (-> attrs :stroke-linecap sr/translate-stroke-linecap) (-> attrs :strokeLinecap sr/translate-stroke-linecap))
|
||||
stroke-linejoin (or (-> attrs :stroke-linejoin sr/translate-stroke-linejoin) (-> attrs :strokeLinejoin sr/translate-stroke-linejoin))
|
||||
fill-none (= "none" (-> attrs :fill))]
|
||||
(h/call wasm/internal-module "_set_shape_svg_attrs" fill-rule stroke-linecap stroke-linejoin fill-none)))
|
||||
|
||||
@@ -786,10 +785,19 @@
|
||||
hidden)))
|
||||
shadows))
|
||||
|
||||
(defn fonts-from-text-content [content fallback-fonts-only?]
|
||||
(defn set-shape-text-content
|
||||
"This function sets shape text content and returns a stream that loads the needed fonts asynchronously"
|
||||
[shape-id content]
|
||||
|
||||
(h/call wasm/internal-module "_clear_shape_text")
|
||||
|
||||
(set-shape-vertical-align (get content :vertical-align))
|
||||
|
||||
(let [paragraph-set (first (get content :children))
|
||||
paragraphs (get paragraph-set :children)
|
||||
fonts (fonts/get-content-fonts content)
|
||||
total (count paragraphs)]
|
||||
|
||||
(loop [index 0
|
||||
emoji? false
|
||||
langs #{}]
|
||||
@@ -806,36 +814,20 @@
|
||||
emoji? (if emoji? emoji? (t/contains-emoji? text))
|
||||
langs (t/collect-used-languages langs text)]
|
||||
|
||||
;; FIXME: this should probably be somewhere else
|
||||
(when fallback-fonts-only? (t/write-shape-text spans paragraph text))
|
||||
|
||||
(t/write-shape-text spans paragraph text)
|
||||
(recur (inc index)
|
||||
emoji?
|
||||
langs))))
|
||||
|
||||
(let [updated-fonts
|
||||
(-> #{}
|
||||
(-> fonts
|
||||
(cond-> ^boolean emoji? (f/add-emoji-font))
|
||||
(f/add-noto-fonts langs))
|
||||
fallback-fonts (filter #(get % :is-fallback) updated-fonts)]
|
||||
result (f/store-fonts shape-id updated-fonts)]
|
||||
|
||||
(if fallback-fonts-only? updated-fonts fallback-fonts))))))
|
||||
(h/call wasm/internal-module "_update_shape_text_layout")
|
||||
|
||||
(defn set-shape-text-content
|
||||
"This function sets shape text content and returns a stream that loads the needed fonts asynchronously"
|
||||
[shape-id content]
|
||||
|
||||
(h/call wasm/internal-module "_clear_shape_text")
|
||||
|
||||
(set-shape-vertical-align (get content :vertical-align))
|
||||
|
||||
(let [fonts (fonts/get-content-fonts content)
|
||||
fallback-fonts (fonts-from-text-content content true)
|
||||
all-fonts (concat fonts fallback-fonts)
|
||||
result (f/store-fonts shape-id all-fonts)]
|
||||
(f/load-fallback-fonts-for-editor! fallback-fonts)
|
||||
(h/call wasm/internal-module "_update_shape_text_layout")
|
||||
result))
|
||||
result)))))
|
||||
|
||||
(defn set-shape-grow-type
|
||||
[grow-type]
|
||||
@@ -1220,6 +1212,7 @@
|
||||
|
||||
(defn init-canvas-context
|
||||
[canvas]
|
||||
|
||||
(let [gl (unchecked-get wasm/internal-module "GL")
|
||||
flags (debug-flags)
|
||||
context-id (if (dbg/enabled? :wasm-gl-context-init-error) "fail" "webgl2")
|
||||
@@ -1266,6 +1259,19 @@
|
||||
(h/call wasm/internal-module "_hide_grid")
|
||||
(request-render "clear-grid"))
|
||||
|
||||
;; Text Editor Functions
|
||||
(defn handle-text-keydown
|
||||
[key]
|
||||
(when (and wasm/internal-module key)
|
||||
(h/call wasm/internal-module "_handle_keydown" key)
|
||||
(request-render "text-editor-keydown")))
|
||||
|
||||
(defn handle-text-mousedown
|
||||
[x y]
|
||||
(when (and wasm/internal-module x y)
|
||||
(h/call wasm/internal-module "_handle_mousedown" x y)
|
||||
(request-render "text-editor-mousedown")))
|
||||
|
||||
(defn get-grid-coords
|
||||
[position]
|
||||
(let [offset (h/call wasm/internal-module
|
||||
@@ -1362,7 +1368,7 @@
|
||||
(delay
|
||||
(if (exists? js/dynamicImport)
|
||||
(let [uri (cf/resolve-static-asset "js/render_wasm.js")]
|
||||
(->> (mod/import uri)
|
||||
(->> (js/dynamicImport (str uri))
|
||||
(p/mcat init-wasm-module)
|
||||
(p/fmap
|
||||
(fn [default]
|
||||
|
||||
@@ -266,12 +266,6 @@
|
||||
|
||||
(store-font-id shape-id font-data asset-id emoji? fallback?)))
|
||||
|
||||
;; FIXME: This is a temporary function to load the fallback fonts for the editor.
|
||||
;; Once we render the editor content within wasm, we can remove this function.
|
||||
(defn load-fallback-fonts-for-editor!
|
||||
[fonts]
|
||||
(doseq [font fonts]
|
||||
(fonts/ensure-loaded! (:font-id font) (:font-variant-id font))))
|
||||
|
||||
(defn store-fonts
|
||||
[shape-id fonts]
|
||||
@@ -283,8 +277,7 @@
|
||||
:font-variant-id "regular"
|
||||
:style 0
|
||||
:weight 400
|
||||
:is-emoji true
|
||||
:is-fallback true}))
|
||||
:is-emoji true}))
|
||||
|
||||
(def noto-fonts
|
||||
{:japanese {:font-id "gfont-noto-sans-jp" :font-variant-id "regular" :style 0 :weight 400 :is-fallback true}
|
||||
|
||||
@@ -67,17 +67,15 @@ function filterAllowedTypes(options) {
|
||||
* @param {string} type
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function filter(type) {
|
||||
return function filter(type) {
|
||||
if (
|
||||
(!("allowHTMLPaste" in options) || !options["allowHTMLPaste"]) &&
|
||||
type === "text/html"
|
||||
type === "text/html"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return allowedTypes.includes(type);
|
||||
};
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,22 +85,19 @@ function filterAllowedTypes(options) {
|
||||
* @returns {Function<AllowedTypesFilterFunction>}
|
||||
*/
|
||||
function filterAllowedItems(options) {
|
||||
|
||||
/**
|
||||
* @param {DataTransferItem}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function filter(item) {
|
||||
return function filter(item) {
|
||||
if (
|
||||
(!("allowHTMLPaste" in options) || !options["allowHTMLPaste"]) &&
|
||||
item.type === "text/html"
|
||||
item.type === "text/html"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return allowedTypes.includes(item.type);
|
||||
};
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
|
||||
(ns app.util.code-highlight
|
||||
(:require
|
||||
["highlight.js$default" :as hljs]
|
||||
["@penpot/hljs" :as hljs]
|
||||
[app.util.dom :as dom]))
|
||||
|
||||
(defn highlight!
|
||||
{:lazy-loadable true}
|
||||
[node]
|
||||
(dom/set-data! node "highlighted" nil)
|
||||
(hljs/highlightElement node))
|
||||
|
||||
@@ -20,7 +20,7 @@ goog.provide("app.util.globals");
|
||||
goog.scope(function () {
|
||||
var self = app.util.globals;
|
||||
|
||||
self.global = globalThis;
|
||||
self.global = goog.global;
|
||||
|
||||
function createMockedEventEmitter(k) {
|
||||
/* Allow mocked objects to be event emitters, so other modules
|
||||
|
||||
@@ -92,9 +92,8 @@
|
||||
is executed in the critical part (application bootstrap) and used in
|
||||
many parts of the application."
|
||||
[data]
|
||||
(set! translations data)
|
||||
(reset! locale (or (get storage/global ::locale) (autodetect))))
|
||||
|
||||
(reset! locale (or (get storage/global ::locale) (autodetect)))
|
||||
(set! translations data))
|
||||
|
||||
(defn set-locale!
|
||||
[lname]
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
;; 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
|
||||
|
||||
(ns app.util.modules
|
||||
(:refer-clojure :exclude [load resolve]))
|
||||
|
||||
(defmacro load
|
||||
[thing]
|
||||
`(-> (shadow.esm/load-by-name ~thing)
|
||||
(.then (fn [f#] (cljs.core/js-obj "default" (f#))))))
|
||||
|
||||
(defmacro load-fn
|
||||
[thing]
|
||||
`(shadow.esm/load-by-name ~thing))
|
||||
@@ -1,16 +0,0 @@
|
||||
;; 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
|
||||
|
||||
(ns app.util.modules
|
||||
(:refer-clojure :exclude [import])
|
||||
(:require-macros [app.util.modules])
|
||||
(:require
|
||||
[shadow.esm :refer [dynamic-import]]))
|
||||
|
||||
(defn import
|
||||
"Dynamic esm module import import"
|
||||
[path]
|
||||
(dynamic-import (str path)))
|
||||
@@ -38,8 +38,7 @@
|
||||
(str v "px")
|
||||
|
||||
(and (= k :font-family) (seq v))
|
||||
;; pick just first family, avoid quoting twice, and add var(--fallback-families)
|
||||
(str/concat (str/quote (str/unquote (first (str/split v ",")))) ", var(--fallback-families)")
|
||||
(str/quote v)
|
||||
|
||||
:else
|
||||
v))
|
||||
@@ -54,7 +53,7 @@
|
||||
(str/slice v 0 -2)
|
||||
|
||||
(= k :font-family)
|
||||
(str/unquote (str/replace v ", var(--fallback-families)" ""))
|
||||
(str/unquote v)
|
||||
|
||||
:else
|
||||
v))
|
||||
|
||||
@@ -101,8 +101,8 @@
|
||||
(rx/push! bus message))))
|
||||
|
||||
handle-error
|
||||
(fn [event]
|
||||
(on-error worker (.-data event)))]
|
||||
(fn [error]
|
||||
(on-error worker (.-data error)))]
|
||||
|
||||
(.addEventListener instance "message" handle-message)
|
||||
(.addEventListener instance "error" handle-error)
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.render-wasm.wasm :as wasm]
|
||||
[app.util.http :as http]
|
||||
[app.util.modules :as mod]
|
||||
[app.worker.impl :as impl]
|
||||
[beicon.v2.core :as rx]
|
||||
[okulary.core :as l]
|
||||
[promesa.core :as p]
|
||||
[rumext.v2 :as mf]))
|
||||
[rumext.v2 :as mf]
|
||||
[shadow.esm :refer (dynamic-import)]))
|
||||
|
||||
(log/set-level! :trace)
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
(def init-wasm
|
||||
(delay
|
||||
(let [uri (cf/resolve-static-asset "js/render_wasm.js")]
|
||||
(-> (mod/import (str uri))
|
||||
(-> (dynamic-import (str uri))
|
||||
(p/then #(wasm.api/init-wasm-module %))
|
||||
(p/then #(set! wasm/internal-module %))))))
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
isLikeParagraph,
|
||||
} from "./Paragraph.js";
|
||||
import { isDisplayBlock, normalizeStyles } from "./Style.js";
|
||||
import { sanitizeFontFamily } from "./Style.js";
|
||||
|
||||
const DEFAULT_FONT_SIZE = "14px";
|
||||
const DEFAULT_FONT_WEIGHT = 400;
|
||||
@@ -88,16 +87,16 @@ export function mapContentFragmentFromDocument(document, root, styleDefaults) {
|
||||
styleDefaults?.getPropertyValue("font-size") ?? DEFAULT_FONT_SIZE,
|
||||
);
|
||||
}
|
||||
let fontFamily = textSpan.style.getPropertyValue("font-family");
|
||||
const fontFamily = textSpan.style.getPropertyValue("font-family");
|
||||
if (!fontFamily) {
|
||||
console.warn("font-family", fontFamily);
|
||||
fontFamily =
|
||||
const fontFamilyValue =
|
||||
styleDefaults?.getPropertyValue("font-family") ?? DEFAULT_FONT_FAMILY;
|
||||
const quotedFontFamily = fontFamilyValue.startsWith('"')
|
||||
? fontFamilyValue
|
||||
: `"${fontFamilyValue}"`;
|
||||
textSpan.style.setProperty("font-family", quotedFontFamily);
|
||||
}
|
||||
|
||||
fontFamily = sanitizeFontFamily(fontFamily);
|
||||
textSpan.style.setProperty("font-family", fontFamily);
|
||||
|
||||
const fontWeight = textSpan.style.getPropertyValue("font-weight");
|
||||
if (!fontWeight) {
|
||||
console.warn("font-weight", fontWeight);
|
||||
@@ -145,29 +144,18 @@ export function htmlToText(html) {
|
||||
tmp.innerHTML = html;
|
||||
|
||||
const blockTags = [
|
||||
"P",
|
||||
"DIV",
|
||||
"SECTION",
|
||||
"ARTICLE",
|
||||
"HEADER",
|
||||
"FOOTER",
|
||||
"UL",
|
||||
"OL",
|
||||
"LI",
|
||||
"TABLE",
|
||||
"TR",
|
||||
"TD",
|
||||
"TH",
|
||||
"PRE",
|
||||
"P", "DIV", "SECTION", "ARTICLE", "HEADER", "FOOTER",
|
||||
"UL", "OL", "LI", "TABLE", "TR", "TD", "TH", "PRE"
|
||||
];
|
||||
|
||||
function walk(node) {
|
||||
let text = "";
|
||||
|
||||
node.childNodes.forEach((child) => {
|
||||
node.childNodes.forEach(child => {
|
||||
if (child.nodeType === Node.TEXT_NODE) {
|
||||
text += child.textContent;
|
||||
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
||||
|
||||
if (child.tagName === "BR") {
|
||||
text += "\n";
|
||||
}
|
||||
@@ -190,6 +178,7 @@ export function htmlToText(html) {
|
||||
return result.trim();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Maps any HTML into a valid content DOM element.
|
||||
*
|
||||
@@ -198,14 +187,10 @@ export function htmlToText(html) {
|
||||
* @param {boolean} [allowHTMLPaste=false]
|
||||
* @returns {DocumentFragment}
|
||||
*/
|
||||
export function mapContentFragmentFromHTML(
|
||||
html,
|
||||
styleDefaults,
|
||||
allowHTMLPaste,
|
||||
) {
|
||||
export function mapContentFragmentFromHTML(html, styleDefaults, allowHTMLPaste) {
|
||||
if (allowHTMLPaste) {
|
||||
try {
|
||||
const parser = new DOMParser();
|
||||
const parser = new DOMParser()
|
||||
const document = parser.parseFromString(html, "text/html");
|
||||
return mapContentFragmentFromDocument(document, styleDefaults);
|
||||
} catch (error) {
|
||||
|
||||
@@ -19,31 +19,10 @@ const DEFAULT_FONT_WEIGHT = "400";
|
||||
* @param {string} value
|
||||
*/
|
||||
export function sanitizeFontFamily(value) {
|
||||
// NOTE: This is a fix for a bug introduced earlier that have might modified the font-family in the model
|
||||
// adding extra double quotes.
|
||||
if (value && value.startsWith('""')) {
|
||||
//remove the first and last quotes
|
||||
value = value.slice(1).replace(/"([^"]*)$/, "$1");
|
||||
|
||||
// remove quotes from font-family in 1-word font-families
|
||||
// and repeated values
|
||||
value = [
|
||||
...new Set(
|
||||
value
|
||||
.split(", ")
|
||||
.map((x) => (x.includes(" ") ? x : x.replace(/"/g, ""))),
|
||||
),
|
||||
].join(", ");
|
||||
}
|
||||
|
||||
if (!value || value === "") {
|
||||
return "var(--fallback-families)";
|
||||
} else if (value.endsWith(" var(--fallback-families)")) {
|
||||
return value;
|
||||
} else if (value.startsWith('"')) {
|
||||
return `${value}, var(--fallback-families)`;
|
||||
if (value && value.length > 0 && !value.startsWith('"')) {
|
||||
return `"${value}"`;
|
||||
} else {
|
||||
return `"${value}", var(--fallback-families)`;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,7 @@ export const {
|
||||
RichTextEditorUtil,
|
||||
SelectionState,
|
||||
convertFromRaw,
|
||||
convertToRaw,
|
||||
EditorBlock,
|
||||
Editor
|
||||
convertToRaw
|
||||
} = pkg;
|
||||
|
||||
import DraftPasteProcessor from 'draft-js/lib/DraftPasteProcessor.js';
|
||||
@@ -8,8 +8,7 @@
|
||||
"author": "Andrey Antukh",
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"draft-js": "penpot/draft-js.git#4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0",
|
||||
"immutable": "^5.1.4"
|
||||
"draft-js": "penpot/draft-js.git#4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=0.17.0",
|
||||
@@ -173,13 +173,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@penpot/draft-js@workspace:.":
|
||||
"@penpot/draft-js-wrapper@workspace:.":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@penpot/draft-js@workspace:."
|
||||
resolution: "@penpot/draft-js-wrapper@workspace:."
|
||||
dependencies:
|
||||
draft-js: "penpot/draft-js.git#4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0"
|
||||
esbuild: "npm:^0.24.0"
|
||||
immutable: "npm:^5.1.4"
|
||||
peerDependencies:
|
||||
react: ">=0.17.0"
|
||||
react-dom: ">=0.17.0"
|
||||
@@ -321,13 +320,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"immutable@npm:^5.1.4":
|
||||
version: 5.1.4
|
||||
resolution: "immutable@npm:5.1.4"
|
||||
checksum: 10c0/f1c98382e4cde14a0b218be3b9b2f8441888da8df3b8c064aa756071da55fbed6ad696e5959982508456332419be9fdeaf29b2e58d0eadc45483cc16963c0446
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"immutable@npm:~3.7.4":
|
||||
version: 3.7.6
|
||||
resolution: "immutable@npm:3.7.6"
|
||||
5
frontend/vendor/hljs/index.js
vendored
Normal file
5
frontend/vendor/hljs/index.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import h from "highlight.js";
|
||||
|
||||
export function highlightElement(node) {
|
||||
return h.highlightElement(node);
|
||||
}
|
||||
13
frontend/vendor/hljs/package.json
vendored
Normal file
13
frontend/vendor/hljs/package.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "@penpot/hljs",
|
||||
"version": "1.0.0",
|
||||
"description": "Penpot Hightlight.js ESM wrapper",
|
||||
"main": "index.js",
|
||||
"packageManager": "yarn@4.3.1",
|
||||
"author": "Andrey Antukh",
|
||||
"license": "MPL-2.0",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"highlight.js": "^11.10.0"
|
||||
}
|
||||
}
|
||||
21
frontend/vendor/hljs/yarn.lock
vendored
Normal file
21
frontend/vendor/hljs/yarn.lock
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# This file is generated by running "yarn install" inside your project.
|
||||
# Manual changes might be lost - proceed with caution!
|
||||
|
||||
__metadata:
|
||||
version: 8
|
||||
cacheKey: 10c0
|
||||
|
||||
"@penpot/hljs@workspace:.":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@penpot/hljs@workspace:."
|
||||
dependencies:
|
||||
highlight.js: "npm:^11.10.0"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"highlight.js@npm:^11.10.0":
|
||||
version: 11.10.0
|
||||
resolution: "highlight.js@npm:11.10.0"
|
||||
checksum: 10c0/cd8bf7ef06cbd72ddb83580ecabe769f08f062be8bb82d2eb492d31c17f7480d1f8d14a66fc81deee0601645435f19f04c470510563f847242a41ccff0ab873e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
4
frontend/vendor/tubax/saxjs.cljs
vendored
Normal file
4
frontend/vendor/tubax/saxjs.cljs
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
(ns tubax.saxjs
|
||||
(:require ["sax" :as sax]))
|
||||
|
||||
(goog/exportSymbol "sax" sax)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user