mirror of
https://github.com/penpot/penpot.git
synced 2026-09-14 07:59:36 +00:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
d44c6250ea
81
.opencode/skills/create-pr/SKILL.md
Normal file
81
.opencode/skills/create-pr/SKILL.md
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
name: create-pr
|
||||||
|
description: Create a GitHub PR following Penpot conventions, with a concise engineer-focused description
|
||||||
|
---
|
||||||
|
|
||||||
|
# Create Pull Request
|
||||||
|
|
||||||
|
Create a GitHub PR with proper title format and a concise description that explains reasoning, not implementation details.
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- Opening a new pull request
|
||||||
|
- The user asks to create a PR
|
||||||
|
- Code changes are ready and committed
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
### 1. Verify Prerequisites
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git branch --show-current
|
||||||
|
git log --oneline main..HEAD
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Check if Branch is Pushed
|
||||||
|
|
||||||
|
```bash
|
||||||
|
BRANCH=$(git branch --show-current)
|
||||||
|
if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then
|
||||||
|
echo "Branch is pushed, proceeding with PR creation"
|
||||||
|
else
|
||||||
|
echo "ERROR: Branch '$BRANCH' is not pushed to remote. Please push the branch first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**If the branch is not pushed, STOP here and ask the user to push it. The LLM does not have push permissions.**
|
||||||
|
|
||||||
|
### 3. Create PR Body
|
||||||
|
|
||||||
|
Write to `/tmp/pr-body.md` to avoid shell quoting issues:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat > /tmp/pr-body.md << 'EOF'
|
||||||
|
**Note:** This PR was created with AI assistance.
|
||||||
|
|
||||||
|
## What
|
||||||
|
|
||||||
|
<one paragraph: the problem or feature, user-facing impact>
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
<root cause or motivation, why this change was necessary>
|
||||||
|
|
||||||
|
## How
|
||||||
|
|
||||||
|
<high-level approach, key technical decisions>
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Create the PR
|
||||||
|
|
||||||
|
Follow title and description format from `mem:workflow/creating-prs` and `mem:workflow/creating-commits`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh pr create --base main --project "Main" --title "<title>" --body-file /tmp/pr-body.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. What NOT to Include
|
||||||
|
|
||||||
|
- ❌ List of files changed (visible in diff)
|
||||||
|
- ❌ Testing steps (CI handles this)
|
||||||
|
- ❌ Screenshots unless UI-visible
|
||||||
|
- ❌ Migration notes unless breaking changes
|
||||||
|
- ❌ Regression fixes introduced during the PR (they're part of the development process, not the feature)
|
||||||
|
|
||||||
|
## Key Principles
|
||||||
|
|
||||||
|
- **Write for humans.** The diff shows what changed. The description explains why.
|
||||||
|
- **Be concise.** Focus on reasoning: What was the problem? Why did it happen? How did you solve it?
|
||||||
|
- **Skip the obvious.** Don't explain what `git diff` already shows.
|
||||||
@ -112,7 +112,7 @@
|
|||||||
- Fix exported path with strokes being cut off in SVG file [#9995](https://github.com/penpot/penpot/issues/9995) (PR: [#9996](https://github.com/penpot/penpot/pull/9996))
|
- Fix exported path with strokes being cut off in SVG file [#9995](https://github.com/penpot/penpot/issues/9995) (PR: [#9996](https://github.com/penpot/penpot/pull/9996))
|
||||||
- Fix French Canada locale falling back to French translations instead of French Canadian (by @alexismo) [#10017](https://github.com/penpot/penpot/issues/10017) (PR: [#10027](https://github.com/penpot/penpot/pull/10027))
|
- Fix French Canada locale falling back to French translations instead of French Canadian (by @alexismo) [#10017](https://github.com/penpot/penpot/issues/10017) (PR: [#10027](https://github.com/penpot/penpot/pull/10027))
|
||||||
|
|
||||||
## 2.16.0 (Unreleased)
|
## 2.16.0
|
||||||
|
|
||||||
### :boom: Breaking changes & Deprecations
|
### :boom: Breaking changes & Deprecations
|
||||||
|
|
||||||
|
|||||||
@ -311,11 +311,30 @@
|
|||||||
:object-id object-id
|
:object-id object-id
|
||||||
:tag tag})))
|
:tag tag})))
|
||||||
|
|
||||||
|
(defn- delete-file-object-thumbnails!
|
||||||
|
"Soft-deletes multiple object thumbnails in a single UPDATE statement
|
||||||
|
with RETURNING, then touches all returned media objects."
|
||||||
|
[{:keys [::db/conn ::sto/storage]} object-ids]
|
||||||
|
(let [ids (db/create-array conn "text" (seq object-ids))
|
||||||
|
sql (str/concat
|
||||||
|
"UPDATE file_tagged_object_thumbnail"
|
||||||
|
" SET deleted_at = now()"
|
||||||
|
" WHERE object_id = ANY(?)"
|
||||||
|
" AND deleted_at IS NULL"
|
||||||
|
" RETURNING media_id")
|
||||||
|
rows (db/exec! conn [sql ids])]
|
||||||
|
(doseq [{:keys [media-id]} rows]
|
||||||
|
(sto/touch-object! storage media-id))))
|
||||||
|
|
||||||
(def ^:private schema:delete-file-object-thumbnail
|
(def ^:private schema:delete-file-object-thumbnail
|
||||||
[:map {:title "delete-file-object-thumbnail"}
|
[:map {:title "delete-file-object-thumbnail"}
|
||||||
[:file-id ::sm/uuid]
|
[:file-id ::sm/uuid]
|
||||||
[:object-id [:string {:max 250}]]])
|
[:object-id [:string {:max 250}]]])
|
||||||
|
|
||||||
|
(def ^:private schema:delete-file-object-thumbnails
|
||||||
|
[:map {:title "delete-file-object-thumbnails"}
|
||||||
|
[:object-ids [:vector {:max 200} [:string {:max 250}]]]])
|
||||||
|
|
||||||
(sv/defmethod ::delete-file-object-thumbnail
|
(sv/defmethod ::delete-file-object-thumbnail
|
||||||
{::doc/added "1.19"
|
{::doc/added "1.19"
|
||||||
::doc/module :files
|
::doc/module :files
|
||||||
@ -329,6 +348,30 @@
|
|||||||
(delete-file-object-thumbnail! file-id object-id))
|
(delete-file-object-thumbnail! file-id object-id))
|
||||||
nil)))
|
nil)))
|
||||||
|
|
||||||
|
(sv/defmethod ::delete-file-object-thumbnails
|
||||||
|
{::doc/added "1.19"
|
||||||
|
::doc/module :files
|
||||||
|
::climit/id [[:file-thumbnail-ops/by-profile ::rpc/profile-id]
|
||||||
|
[:file-thumbnail-ops/global]]
|
||||||
|
::sm/params schema:delete-file-object-thumbnails
|
||||||
|
::audit/skip true}
|
||||||
|
[cfg {:keys [::rpc/profile-id object-ids]}]
|
||||||
|
(when (seq object-ids)
|
||||||
|
;; Extract unique file-ids from object-ids for permission checks
|
||||||
|
(let [file-ids (->> object-ids
|
||||||
|
(map thc/get-file-id)
|
||||||
|
(into #{}))]
|
||||||
|
;; Check permissions for each unique file using a single connection
|
||||||
|
(db/run! cfg (fn [{:keys [::db/conn]}]
|
||||||
|
(doseq [file-id file-ids]
|
||||||
|
(files/check-edition-permissions! conn profile-id file-id))))
|
||||||
|
;; Delete all matching thumbnails in one transaction
|
||||||
|
(db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}]
|
||||||
|
(-> cfg
|
||||||
|
(update ::sto/storage sto/configure conn)
|
||||||
|
(delete-file-object-thumbnails! object-ids))
|
||||||
|
nil)))))
|
||||||
|
|
||||||
;; --- MUTATION COMMAND: create-file-thumbnail
|
;; --- MUTATION COMMAND: create-file-thumbnail
|
||||||
|
|
||||||
(defn- create-file-thumbnail
|
(defn- create-file-thumbnail
|
||||||
|
|||||||
@ -380,3 +380,538 @@
|
|||||||
(t/is (nil? (:error out)))
|
(t/is (nil? (:error out)))
|
||||||
(t/is (map? (:result out))))))
|
(t/is (map? (:result out))))))
|
||||||
|
|
||||||
|
;; --- delete-file-object-thumbnails (batch)
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-basic
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page-id (first (get-in file [:data :pages]))
|
||||||
|
oid1 (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")
|
||||||
|
oid2 (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")
|
||||||
|
oid3 (thc/fmt-object-id (:id file) page-id (uuid/random) "component")]
|
||||||
|
|
||||||
|
;; Create three thumbnails
|
||||||
|
(doseq [oid [oid1 oid2 oid3]]
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id (:id file)
|
||||||
|
:object-id oid
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out)))))
|
||||||
|
|
||||||
|
;; Verify all three exist and are not soft-deleted
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{::db/remove-deleted false
|
||||||
|
:order-by [[:created-at :asc]]})]
|
||||||
|
(t/is (= 3 (count rows)))
|
||||||
|
(doseq [row rows]
|
||||||
|
(t/is (nil? (:deleted-at row)))))
|
||||||
|
|
||||||
|
;; Batch delete all three
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid1 oid2 oid3]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; Verify all three are now soft-deleted
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{::db/remove-deleted false
|
||||||
|
:order-by [[:created-at :asc]]})]
|
||||||
|
(t/is (= 3 (count rows)))
|
||||||
|
(doseq [row rows]
|
||||||
|
(t/is (some? (:deleted-at row)))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-empty
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids []}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out)))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-non-existent
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page-id (first (get-in file [:data :pages]))
|
||||||
|
oid1 (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")
|
||||||
|
oid2 (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; Batch delete non-existent object-ids (no thumbnails were created)
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid1 oid2]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-mixed-exists
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page-id (first (get-in file [:data :pages]))
|
||||||
|
oid1 (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")
|
||||||
|
oid2 (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")
|
||||||
|
oid3 (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; Create only one thumbnail
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id (:id file)
|
||||||
|
:object-id oid1
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out))))
|
||||||
|
|
||||||
|
;; Batch delete mix of existing and non-existing
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid1 oid2 oid3]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; Verify oid1 is soft-deleted, others don't exist
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= 1 (count rows)))
|
||||||
|
(t/is (= oid1 (:object-id (first rows))))
|
||||||
|
(t/is (some? (:deleted-at (first rows)))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-already-deleted
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page-id (first (get-in file [:data :pages]))
|
||||||
|
oid (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; Create a thumbnail
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id (:id file)
|
||||||
|
:object-id oid
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out))))
|
||||||
|
|
||||||
|
;; First batch delete
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; Second batch delete (idempotent — no rows match deleted_at IS NULL)
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; Verify still 1 row, still soft-deleted, not duplicated
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= 1 (count rows)))
|
||||||
|
(t/is (= oid (:object-id (first rows))))
|
||||||
|
(t/is (some? (:deleted-at (first rows)))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-unauthorized
|
||||||
|
(let [profile1 (th/create-profile* 1)
|
||||||
|
profile2 (th/create-profile* 2)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile1)
|
||||||
|
:project-id (:default-project-id profile1)
|
||||||
|
:is-shared false})
|
||||||
|
page-id (first (get-in file [:data :pages]))
|
||||||
|
oid (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; profile1 creates a thumbnail on their file
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile1)
|
||||||
|
:file-id (:id file)
|
||||||
|
:object-id oid
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out))))
|
||||||
|
|
||||||
|
;; profile2 tries to batch delete thumbnails from profile1's file
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile2)
|
||||||
|
:object-ids [oid]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (some? (:error out)))
|
||||||
|
(t/is (th/ex-info? (:error out)))
|
||||||
|
(t/is (= :not-found (th/ex-type (:error out)))))
|
||||||
|
|
||||||
|
;; Verify the thumbnail is NOT deleted
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= 1 (count rows)))
|
||||||
|
(t/is (nil? (:deleted-at (first rows)))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-cross-file
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file1 (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
file2 (th/create-file* 2 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page1-id (first (get-in file1 [:data :pages]))
|
||||||
|
page2-id (first (get-in file2 [:data :pages]))
|
||||||
|
oid1 (thc/fmt-object-id (:id file1) page1-id (uuid/random) "frame")
|
||||||
|
oid2 (thc/fmt-object-id (:id file2) page2-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; Create thumbnails on both files
|
||||||
|
(doseq [[oid fid] [[oid1 (:id file1)] [oid2 (:id file2)]]]
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id fid
|
||||||
|
:object-id oid
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out)))))
|
||||||
|
|
||||||
|
;; Batch delete from both files in one call
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid1 oid2]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; Verify both are soft-deleted
|
||||||
|
(let [rows1 (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file1)}
|
||||||
|
{::db/remove-deleted false})
|
||||||
|
rows2 (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file2)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= 1 (count rows1)))
|
||||||
|
(t/is (some? (:deleted-at (first rows1))))
|
||||||
|
(t/is (= 1 (count rows2)))
|
||||||
|
(t/is (some? (:deleted-at (first rows2)))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-cross-file-unauthorized
|
||||||
|
(let [profile1 (th/create-profile* 1)
|
||||||
|
profile2 (th/create-profile* 2)
|
||||||
|
file1 (th/create-file* 1 {:profile-id (:id profile1)
|
||||||
|
:project-id (:default-project-id profile1)
|
||||||
|
:is-shared false})
|
||||||
|
file2 (th/create-file* 2 {:profile-id (:id profile2)
|
||||||
|
:project-id (:default-project-id profile2)
|
||||||
|
:is-shared false})
|
||||||
|
page1-id (first (get-in file1 [:data :pages]))
|
||||||
|
page2-id (first (get-in file2 [:data :pages]))
|
||||||
|
oid1 (thc/fmt-object-id (:id file1) page1-id (uuid/random) "frame")
|
||||||
|
oid2 (thc/fmt-object-id (:id file2) page2-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; Create thumbnails on both files (by their respective owners)
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile1)
|
||||||
|
:file-id (:id file1)
|
||||||
|
:object-id oid1
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out))))
|
||||||
|
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile2)
|
||||||
|
:file-id (:id file2)
|
||||||
|
:object-id oid2
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out))))
|
||||||
|
|
||||||
|
;; profile1 tries to batch delete thumbnails from both files
|
||||||
|
;; (profile1 does NOT have access to file2)
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile1)
|
||||||
|
:object-ids [oid1 oid2]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (some? (:error out)))
|
||||||
|
(t/is (th/ex-info? (:error out)))
|
||||||
|
(t/is (= :not-found (th/ex-type (:error out)))))
|
||||||
|
|
||||||
|
;; Verify NEITHER thumbnail was deleted (all-or-nothing)
|
||||||
|
(let [rows1 (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file1)}
|
||||||
|
{::db/remove-deleted false})
|
||||||
|
rows2 (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file2)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= 1 (count rows1)))
|
||||||
|
(t/is (nil? (:deleted-at (first rows1))))
|
||||||
|
(t/is (= 1 (count rows2)))
|
||||||
|
(t/is (nil? (:deleted-at (first rows2)))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-media-touch
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page-id (first (get-in file [:data :pages]))
|
||||||
|
oid1 (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")
|
||||||
|
oid2 (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; Create two thumbnails
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id (:id file)
|
||||||
|
:object-id oid1
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out))))
|
||||||
|
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id (:id file)
|
||||||
|
:object-id oid2
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 312043
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out))))
|
||||||
|
|
||||||
|
;; Get media-ids for both thumbnails
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{:order-by [[:created-at :asc]]})
|
||||||
|
mid1 (:media-id (first rows))
|
||||||
|
mid2 (:media-id (second rows))]
|
||||||
|
|
||||||
|
;; Verify storage objects exist (they are created with touched-at already set)
|
||||||
|
(t/is (some? (th/db-get :storage-object {:id mid1})))
|
||||||
|
(t/is (some? (th/db-get :storage-object {:id mid2})))
|
||||||
|
|
||||||
|
;; Batch delete both thumbnails
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid1 oid2]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; After soft-delete, storage objects should STILL exist
|
||||||
|
;; (they are only garbage-collected later by storage-gc-touched task)
|
||||||
|
(t/is (some? (th/db-get :storage-object {:id mid1})))
|
||||||
|
(t/is (some? (th/db-get :storage-object {:id mid2}))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-max-batch
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page-id (first (get-in file [:data :pages]))
|
||||||
|
cnt 200
|
||||||
|
oids (vec (repeatedly cnt
|
||||||
|
#(thc/fmt-object-id (:id file) page-id
|
||||||
|
(uuid/random) "frame")))]
|
||||||
|
|
||||||
|
;; Create 200 thumbnails
|
||||||
|
(doseq [oid oids]
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id (:id file)
|
||||||
|
:object-id oid
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out)))))
|
||||||
|
|
||||||
|
;; Verify all 200 exist
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= cnt (count rows))))
|
||||||
|
|
||||||
|
;; Batch delete all 200 in one call
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids oids}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; Verify all 200 are now soft-deleted
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= cnt (count rows)))
|
||||||
|
(doseq [row rows]
|
||||||
|
(t/is (some? (:deleted-at row)))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-single
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page-id (first (get-in file [:data :pages]))
|
||||||
|
oid (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; Create a single thumbnail
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id (:id file)
|
||||||
|
:object-id oid
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out))))
|
||||||
|
|
||||||
|
;; Batch delete just one
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; Verify it's soft-deleted
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= 1 (count rows)))
|
||||||
|
(t/is (some? (:deleted-at (first rows)))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-same-object-twice-in-batch
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page-id (first (get-in file [:data :pages]))
|
||||||
|
oid (thc/fmt-object-id (:id file) page-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; Create one thumbnail
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id (:id file)
|
||||||
|
:object-id oid
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out))))
|
||||||
|
|
||||||
|
;; Batch delete with the same object-id listed twice
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid oid]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; Verify it's soft-deleted (only one row)
|
||||||
|
(let [rows (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= 1 (count rows)))
|
||||||
|
(t/is (some? (:deleted-at (first rows)))))))
|
||||||
|
|
||||||
|
(t/deftest delete-file-object-thumbnails-keeps-other-files-intact
|
||||||
|
(let [profile (th/create-profile* 1)
|
||||||
|
file1 (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
file2 (th/create-file* 2 {:profile-id (:id profile)
|
||||||
|
:project-id (:default-project-id profile)
|
||||||
|
:is-shared false})
|
||||||
|
page1-id (first (get-in file1 [:data :pages]))
|
||||||
|
page2-id (first (get-in file2 [:data :pages]))
|
||||||
|
oid1 (thc/fmt-object-id (:id file1) page1-id (uuid/random) "frame")
|
||||||
|
oid2 (thc/fmt-object-id (:id file2) page2-id (uuid/random) "frame")]
|
||||||
|
|
||||||
|
;; Create thumbnails on both files
|
||||||
|
(doseq [[oid fid] [[oid1 (:id file1)] [oid2 (:id file2)]]]
|
||||||
|
(let [data {::th/type :create-file-object-thumbnail
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:file-id fid
|
||||||
|
:object-id oid
|
||||||
|
:media {:filename "sample.jpg"
|
||||||
|
:size 7923
|
||||||
|
:path (th/tempfile "backend_tests/test_files/sample2.jpg")
|
||||||
|
:mtype "image/jpeg"}}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (map? (:result out)))))
|
||||||
|
|
||||||
|
;; Delete only thumbnail from file1
|
||||||
|
(let [data {::th/type :delete-file-object-thumbnails
|
||||||
|
::rpc/profile-id (:id profile)
|
||||||
|
:object-ids [oid1]}
|
||||||
|
out (th/command! data)]
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
;; Verify file1's thumbnail is deleted, file2's is not
|
||||||
|
(let [rows1 (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file1)}
|
||||||
|
{::db/remove-deleted false})
|
||||||
|
rows2 (th/db-query :file-tagged-object-thumbnail
|
||||||
|
{:file-id (:id file2)}
|
||||||
|
{::db/remove-deleted false})]
|
||||||
|
(t/is (= 1 (count rows1)))
|
||||||
|
(t/is (some? (:deleted-at (first rows1))))
|
||||||
|
(t/is (= 1 (count rows2)))
|
||||||
|
(t/is (nil? (:deleted-at (first rows2)))))))
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ RUN set -ex; \
|
|||||||
|
|
||||||
FROM base AS setup-node
|
FROM base AS setup-node
|
||||||
|
|
||||||
ENV NODE_VERSION=v24.15.0 \
|
ENV NODE_VERSION=v24.16.0 \
|
||||||
PATH=/opt/node/bin:$PATH
|
PATH=/opt/node/bin:$PATH
|
||||||
|
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
|
|||||||
@ -5,7 +5,7 @@ ENV LANG='C.UTF-8' \
|
|||||||
LC_ALL='C.UTF-8' \
|
LC_ALL='C.UTF-8' \
|
||||||
JAVA_HOME="/opt/jdk" \
|
JAVA_HOME="/opt/jdk" \
|
||||||
DEBIAN_FRONTEND=noninteractive \
|
DEBIAN_FRONTEND=noninteractive \
|
||||||
NODE_VERSION=v24.15.0 \
|
NODE_VERSION=v24.16.0 \
|
||||||
TZ=Etc/UTC
|
TZ=Etc/UTC
|
||||||
|
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
@ -16,6 +16,7 @@ RUN set -ex; \
|
|||||||
ca-certificates \
|
ca-certificates \
|
||||||
curl \
|
curl \
|
||||||
; \
|
; \
|
||||||
|
apt-get clean; \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
@ -115,13 +116,13 @@ RUN set -ex; \
|
|||||||
woff2 \
|
woff2 \
|
||||||
; \
|
; \
|
||||||
find tmp/usr/share/zoneinfo/* -type d ! -name 'Etc' |xargs rm -rf; \
|
find tmp/usr/share/zoneinfo/* -type d ! -name 'Etc' |xargs rm -rf; \
|
||||||
|
apt-get clean; \
|
||||||
rm -rf /var/lib /var/cache; \
|
rm -rf /var/lib /var/cache; \
|
||||||
rm -rf /usr/include; \
|
rm -rf /usr/include; \
|
||||||
mkdir -p /opt/data/assets; \
|
mkdir -p /opt/data/assets; \
|
||||||
mkdir -p /opt/penpot; \
|
mkdir -p /opt/penpot; \
|
||||||
chown -R penpot:penpot /opt/penpot; \
|
chown -R penpot:penpot /opt/penpot; \
|
||||||
chown -R penpot:penpot /opt/data; \
|
chown -R penpot:penpot /opt/data;
|
||||||
rm -rf /var/lib/apt/lists/*;
|
|
||||||
|
|
||||||
COPY --from=build /opt/jre /opt/jre
|
COPY --from=build /opt/jre /opt/jre
|
||||||
COPY --from=build /opt/node /opt/node
|
COPY --from=build /opt/node /opt/node
|
||||||
|
|||||||
@ -3,7 +3,7 @@ LABEL maintainer="Penpot <docker@penpot.app>"
|
|||||||
|
|
||||||
ENV LANG=en_US.UTF-8 \
|
ENV LANG=en_US.UTF-8 \
|
||||||
LC_ALL=en_US.UTF-8 \
|
LC_ALL=en_US.UTF-8 \
|
||||||
NODE_VERSION=v24.15.0 \
|
NODE_VERSION=v24.16.0 \
|
||||||
DEBIAN_FRONTEND=noninteractive \
|
DEBIAN_FRONTEND=noninteractive \
|
||||||
PATH=/opt/node/bin:/opt/imagick/bin:$PATH \
|
PATH=/opt/node/bin:/opt/imagick/bin:$PATH \
|
||||||
PLAYWRIGHT_BROWSERS_PATH=/opt/penpot/browsers
|
PLAYWRIGHT_BROWSERS_PATH=/opt/penpot/browsers
|
||||||
@ -20,6 +20,7 @@ RUN set -ex; \
|
|||||||
locales \
|
locales \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
; \
|
; \
|
||||||
|
apt-get clean; \
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
rm -rf /var/lib/apt/lists/*; \
|
||||||
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen; \
|
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen; \
|
||||||
locale-gen; \
|
locale-gen; \
|
||||||
@ -81,6 +82,7 @@ RUN set -ex; \
|
|||||||
libzip4t64 \
|
libzip4t64 \
|
||||||
libzstd1 \
|
libzstd1 \
|
||||||
; \
|
; \
|
||||||
|
apt-get clean; \
|
||||||
rm -rf /var/lib/apt/lists/*;
|
rm -rf /var/lib/apt/lists/*;
|
||||||
|
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
FROM nginxinc/nginx-unprivileged:1.30.0
|
FROM nginxinc/nginx-unprivileged:1.30.2-alpine
|
||||||
LABEL maintainer="Penpot <docker@penpot.app>"
|
LABEL maintainer="Penpot <docker@penpot.app>"
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
useradd -U -M -u 1001 -s /bin/false -d /opt/penpot penpot; \
|
apk update; \
|
||||||
|
apk upgrade; \
|
||||||
|
apk add --no-cache bash gettext; \
|
||||||
|
rm -rf /var/cache/apk/*; \
|
||||||
|
addgroup -g 1001 penpot; \
|
||||||
|
adduser -D -H -u 1001 -s /bin/false -h /opt/penpot -G penpot penpot; \
|
||||||
mkdir -p /opt/data/assets; \
|
mkdir -p /opt/data/assets; \
|
||||||
chown -R penpot:penpot /opt/data; \
|
chown -R penpot:penpot /opt/data; \
|
||||||
mkdir -p /etc/nginx/overrides/main.d/; \
|
mkdir -p /etc/nginx/overrides/main.d/; \
|
||||||
|
|||||||
@ -20,6 +20,7 @@ RUN set -ex; \
|
|||||||
locales \
|
locales \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
; \
|
; \
|
||||||
|
apt-get clean; \
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
rm -rf /var/lib/apt/lists/*; \
|
||||||
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen; \
|
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen; \
|
||||||
locale-gen; \
|
locale-gen; \
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
FROM nginxinc/nginx-unprivileged:1.30.0
|
FROM nginxinc/nginx-unprivileged:1.30.2-alpine
|
||||||
LABEL maintainer="Penpot <docker@penpot.app>"
|
LABEL maintainer="Penpot <docker@penpot.app>"
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
useradd -U -M -u 1001 -s /bin/false -d /opt/penpot penpot;
|
apk update; \
|
||||||
|
apk upgrade; \
|
||||||
|
rm -rf /var/cache/apk/*; \
|
||||||
|
addgroup -g 1001 penpot; \
|
||||||
|
adduser -D -H -u 1001 -s /bin/false -h /opt/penpot -G penpot penpot;
|
||||||
|
|
||||||
ARG BUNDLE_PATH="./bundle-storybook/"
|
ARG BUNDLE_PATH="./bundle-storybook/"
|
||||||
COPY $BUNDLE_PATH /var/www/
|
COPY $BUNDLE_PATH /var/www/
|
||||||
|
|||||||
@ -206,6 +206,12 @@ server {
|
|||||||
proxy_pass http://localhost:9001/ws/notifications;
|
proxy_pass http://localhost:9001/ws/notifications;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /mcp/ws {
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_pass http://localhost:9001/mcp/ws;
|
||||||
|
}
|
||||||
|
|
||||||
# Proxy pass
|
# Proxy pass
|
||||||
location / {
|
location / {
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
"playwright": "^1.60.0",
|
"playwright": "^1.60.0",
|
||||||
"raw-body": "^3.0.2",
|
"raw-body": "^3.0.2",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"svgo": "penpot/svgo#v3.1",
|
"@penpot/svgo": "penpot/svgo#3.3.0",
|
||||||
"undici": "^8.4.1",
|
"undici": "^8.4.1",
|
||||||
"xml-js": "^1.6.11",
|
"xml-js": "^1.6.11",
|
||||||
"xregexp": "^5.1.2"
|
"xregexp": "^5.1.2"
|
||||||
|
|||||||
184
exporter/pnpm-lock.yaml
generated
184
exporter/pnpm-lock.yaml
generated
@ -4,10 +4,18 @@ settings:
|
|||||||
autoInstallPeers: true
|
autoInstallPeers: true
|
||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
overrides:
|
||||||
|
lodash@<=4.17.23: ^4.17.24
|
||||||
|
lodash@>=4.0.0 <=4.17.22: ^4.17.23
|
||||||
|
lodash@>=4.0.0 <=4.17.23: ^4.17.24
|
||||||
|
|
||||||
importers:
|
importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@penpot/svgo':
|
||||||
|
specifier: penpot/svgo#3.3.0
|
||||||
|
version: https://codeload.github.com/penpot/svgo/tar.gz/65b3a645df9edbe3c00acf4267dd06c2ca736021
|
||||||
archiver:
|
archiver:
|
||||||
specifier: 8.0.0
|
specifier: 8.0.0
|
||||||
version: 8.0.0
|
version: 8.0.0
|
||||||
@ -35,9 +43,6 @@ importers:
|
|||||||
source-map-support:
|
source-map-support:
|
||||||
specifier: ^0.5.21
|
specifier: ^0.5.21
|
||||||
version: 0.5.21
|
version: 0.5.21
|
||||||
svgo:
|
|
||||||
specifier: penpot/svgo#v3.1
|
|
||||||
version: https://codeload.github.com/penpot/svgo/tar.gz/a46262c12c0d967708395972c374eb2adead4180
|
|
||||||
undici:
|
undici:
|
||||||
specifier: ^8.4.1
|
specifier: ^8.4.1
|
||||||
version: 8.4.1
|
version: 8.4.1
|
||||||
@ -54,16 +59,16 @@ importers:
|
|||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@babel/runtime-corejs3@7.28.4':
|
'@babel/runtime-corejs3@7.29.7':
|
||||||
resolution: {integrity: sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==}
|
resolution: {integrity: sha512-ppj9ouYku+RX0ljtgZd+KMO5mkM2bCqg8H2PYAFWnLsHEIKIdRojqbJ2i3eVHrisuxy7nOFCmngTDdWtUCdXUQ==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@ioredis/commands@1.10.0':
|
'@ioredis/commands@1.10.0':
|
||||||
resolution: {integrity: sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==}
|
resolution: {integrity: sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==}
|
||||||
|
|
||||||
'@trysound/sax@0.2.0':
|
'@penpot/svgo@https://codeload.github.com/penpot/svgo/tar.gz/65b3a645df9edbe3c00acf4267dd06c2ca736021':
|
||||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
resolution: {gitHosted: true, integrity: sha512-hG/pgVEWhmHEFMU+evGZkB5kHauff5Zo6ZO+Ro7HY0efsQTJft6svM4isH5jDISeSVrZ1CDGnhWBXuqkztsTWw==, tarball: https://codeload.github.com/penpot/svgo/tar.gz/65b3a645df9edbe3c00acf4267dd06c2ca736021}
|
||||||
engines: {node: '>=10.13.0'}
|
version: 3.3.0
|
||||||
|
|
||||||
abort-controller@3.0.0:
|
abort-controller@3.0.0:
|
||||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||||
@ -132,8 +137,9 @@ packages:
|
|||||||
base64-js@1.5.1:
|
base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
|
||||||
boolbase@1.0.0:
|
boolbase@2.0.0:
|
||||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
resolution: {integrity: sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
brace-expansion@5.0.6:
|
brace-expansion@5.0.6:
|
||||||
resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==}
|
resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==}
|
||||||
@ -165,8 +171,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==}
|
resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
core-js-pure@3.47.0:
|
core-js-pure@3.49.0:
|
||||||
resolution: {integrity: sha512-BcxeDbzUrRnXGYIVAGFtcGQVNpFcUhVjr6W7F8XktvQW2iJP9e66GP6xdKotCRFlrxBvNIBrhwKteRXqMV86Nw==}
|
resolution: {integrity: sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==}
|
||||||
|
|
||||||
core-util-is@1.0.3:
|
core-util-is@1.0.3:
|
||||||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||||
@ -180,20 +186,21 @@ packages:
|
|||||||
resolution: {integrity: sha512-IBWsY8xznyQrcHn8h4bC8/4ErNke5elzgG8GcqF4RFPw6aHkWWRc7Tgw6upjaTX/CT/yQgqYENkxYsTYN+hW2g==}
|
resolution: {integrity: sha512-IBWsY8xznyQrcHn8h4bC8/4ErNke5elzgG8GcqF4RFPw6aHkWWRc7Tgw6upjaTX/CT/yQgqYENkxYsTYN+hW2g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
css-select@5.2.2:
|
css-select@7.0.0:
|
||||||
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
|
resolution: {integrity: sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
css-tree@2.2.1:
|
css-tree@2.2.1:
|
||||||
resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
|
resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
|
||||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
|
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
|
||||||
|
|
||||||
css-tree@3.1.0:
|
css-tree@3.2.1:
|
||||||
resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
|
resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
|
||||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
||||||
|
|
||||||
css-what@6.2.2:
|
css-what@8.0.0:
|
||||||
resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
|
resolution: {integrity: sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
csso@5.0.5:
|
csso@5.0.5:
|
||||||
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
|
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
|
||||||
@ -219,22 +226,25 @@ packages:
|
|||||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
dom-serializer@2.0.0:
|
dom-serializer@3.1.1:
|
||||||
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
resolution: {integrity: sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
domelementtype@2.3.0:
|
domelementtype@3.0.0:
|
||||||
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
resolution: {integrity: sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
domhandler@5.0.3:
|
domhandler@6.0.1:
|
||||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
resolution: {integrity: sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
domutils@3.2.2:
|
domutils@4.0.2:
|
||||||
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
resolution: {integrity: sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
entities@4.5.0:
|
entities@8.0.0:
|
||||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
event-target-shim@5.0.1:
|
event-target-shim@5.0.1:
|
||||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||||
@ -263,8 +273,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
iconv-lite@0.7.1:
|
iconv-lite@0.7.2:
|
||||||
resolution: {integrity: sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==}
|
resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
ieee754@1.2.1:
|
ieee754@1.2.1:
|
||||||
@ -291,20 +301,19 @@ packages:
|
|||||||
keygrip@1.1.0:
|
keygrip@1.1.0:
|
||||||
resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==}
|
resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
|
|
||||||
|
|
||||||
lazystream@1.0.1:
|
lazystream@1.0.1:
|
||||||
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
|
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
|
||||||
engines: {node: '>= 0.6.3'}
|
engines: {node: '>= 0.6.3'}
|
||||||
|
|
||||||
lodash@4.17.21:
|
lodash@4.18.1:
|
||||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
|
||||||
|
|
||||||
mdn-data@2.0.28:
|
mdn-data@2.0.28:
|
||||||
resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
|
resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
|
||||||
|
|
||||||
mdn-data@2.12.2:
|
mdn-data@2.27.1:
|
||||||
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
|
resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
|
||||||
|
|
||||||
minimatch@10.2.5:
|
minimatch@10.2.5:
|
||||||
resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
|
resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
|
||||||
@ -317,8 +326,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
nth-check@2.1.1:
|
nth-check@3.0.1:
|
||||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
resolution: {integrity: sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
playwright-core@1.60.0:
|
playwright-core@1.60.0:
|
||||||
resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==}
|
resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==}
|
||||||
@ -369,8 +379,9 @@ packages:
|
|||||||
safer-buffer@2.1.2:
|
safer-buffer@2.1.2:
|
||||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||||
|
|
||||||
sax@1.4.3:
|
sax@1.6.0:
|
||||||
resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==}
|
resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==}
|
||||||
|
engines: {node: '>=11.0.0'}
|
||||||
|
|
||||||
setprototypeof@1.2.0:
|
setprototypeof@1.2.0:
|
||||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
@ -402,11 +413,6 @@ packages:
|
|||||||
string_decoder@1.3.0:
|
string_decoder@1.3.0:
|
||||||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||||
|
|
||||||
svgo@https://codeload.github.com/penpot/svgo/tar.gz/a46262c12c0d967708395972c374eb2adead4180:
|
|
||||||
resolution: {gitHosted: true, tarball: https://codeload.github.com/penpot/svgo/tar.gz/a46262c12c0d967708395972c374eb2adead4180}
|
|
||||||
version: 4.0.0
|
|
||||||
engines: {node: '>=16.0.0'}
|
|
||||||
|
|
||||||
tar-stream@3.2.0:
|
tar-stream@3.2.0:
|
||||||
resolution: {integrity: sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==}
|
resolution: {integrity: sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==}
|
||||||
|
|
||||||
@ -460,13 +466,19 @@ packages:
|
|||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@babel/runtime-corejs3@7.28.4':
|
'@babel/runtime-corejs3@7.29.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
core-js-pure: 3.47.0
|
core-js-pure: 3.49.0
|
||||||
|
|
||||||
'@ioredis/commands@1.10.0': {}
|
'@ioredis/commands@1.10.0': {}
|
||||||
|
|
||||||
'@trysound/sax@0.2.0': {}
|
'@penpot/svgo@https://codeload.github.com/penpot/svgo/tar.gz/65b3a645df9edbe3c00acf4267dd06c2ca736021':
|
||||||
|
dependencies:
|
||||||
|
css-select: 7.0.0
|
||||||
|
css-tree: 3.2.1
|
||||||
|
csso: 5.0.5
|
||||||
|
lodash: 4.18.1
|
||||||
|
sax: 1.6.0
|
||||||
|
|
||||||
abort-controller@3.0.0:
|
abort-controller@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -528,7 +540,7 @@ snapshots:
|
|||||||
|
|
||||||
base64-js@1.5.1: {}
|
base64-js@1.5.1: {}
|
||||||
|
|
||||||
boolbase@1.0.0: {}
|
boolbase@2.0.0: {}
|
||||||
|
|
||||||
brace-expansion@5.0.6:
|
brace-expansion@5.0.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -560,7 +572,7 @@ snapshots:
|
|||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
keygrip: 1.1.0
|
keygrip: 1.1.0
|
||||||
|
|
||||||
core-js-pure@3.47.0: {}
|
core-js-pure@3.49.0: {}
|
||||||
|
|
||||||
core-util-is@1.0.3: {}
|
core-util-is@1.0.3: {}
|
||||||
|
|
||||||
@ -571,25 +583,25 @@ snapshots:
|
|||||||
crc-32: 1.2.2
|
crc-32: 1.2.2
|
||||||
readable-stream: 4.7.0
|
readable-stream: 4.7.0
|
||||||
|
|
||||||
css-select@5.2.2:
|
css-select@7.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 2.0.0
|
||||||
css-what: 6.2.2
|
css-what: 8.0.0
|
||||||
domhandler: 5.0.3
|
domhandler: 6.0.1
|
||||||
domutils: 3.2.2
|
domutils: 4.0.2
|
||||||
nth-check: 2.1.1
|
nth-check: 3.0.1
|
||||||
|
|
||||||
css-tree@2.2.1:
|
css-tree@2.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
mdn-data: 2.0.28
|
mdn-data: 2.0.28
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
css-tree@3.1.0:
|
css-tree@3.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
mdn-data: 2.12.2
|
mdn-data: 2.27.1
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
css-what@6.2.2: {}
|
css-what@8.0.0: {}
|
||||||
|
|
||||||
csso@5.0.5:
|
csso@5.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -605,25 +617,25 @@ snapshots:
|
|||||||
|
|
||||||
depd@2.0.0: {}
|
depd@2.0.0: {}
|
||||||
|
|
||||||
dom-serializer@2.0.0:
|
dom-serializer@3.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 3.0.0
|
||||||
domhandler: 5.0.3
|
domhandler: 6.0.1
|
||||||
entities: 4.5.0
|
entities: 8.0.0
|
||||||
|
|
||||||
domelementtype@2.3.0: {}
|
domelementtype@3.0.0: {}
|
||||||
|
|
||||||
domhandler@5.0.3:
|
domhandler@6.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 3.0.0
|
||||||
|
|
||||||
domutils@3.2.2:
|
domutils@4.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
dom-serializer: 2.0.0
|
dom-serializer: 3.1.1
|
||||||
domelementtype: 2.3.0
|
domelementtype: 3.0.0
|
||||||
domhandler: 5.0.3
|
domhandler: 6.0.1
|
||||||
|
|
||||||
entities@4.5.0: {}
|
entities@8.0.0: {}
|
||||||
|
|
||||||
event-target-shim@5.0.1: {}
|
event-target-shim@5.0.1: {}
|
||||||
|
|
||||||
@ -650,7 +662,7 @@ snapshots:
|
|||||||
statuses: 2.0.2
|
statuses: 2.0.2
|
||||||
toidentifier: 1.0.1
|
toidentifier: 1.0.1
|
||||||
|
|
||||||
iconv-lite@0.7.1:
|
iconv-lite@0.7.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
safer-buffer: 2.1.2
|
safer-buffer: 2.1.2
|
||||||
|
|
||||||
@ -684,11 +696,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
readable-stream: 2.3.8
|
readable-stream: 2.3.8
|
||||||
|
|
||||||
lodash@4.17.21: {}
|
lodash@4.18.1: {}
|
||||||
|
|
||||||
mdn-data@2.0.28: {}
|
mdn-data@2.0.28: {}
|
||||||
|
|
||||||
mdn-data@2.12.2: {}
|
mdn-data@2.27.1: {}
|
||||||
|
|
||||||
minimatch@10.2.5:
|
minimatch@10.2.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -698,9 +710,9 @@ snapshots:
|
|||||||
|
|
||||||
normalize-path@3.0.0: {}
|
normalize-path@3.0.0: {}
|
||||||
|
|
||||||
nth-check@2.1.1:
|
nth-check@3.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 2.0.0
|
||||||
|
|
||||||
playwright-core@1.60.0: {}
|
playwright-core@1.60.0: {}
|
||||||
|
|
||||||
@ -718,7 +730,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
bytes: 3.1.2
|
bytes: 3.1.2
|
||||||
http-errors: 2.0.1
|
http-errors: 2.0.1
|
||||||
iconv-lite: 0.7.1
|
iconv-lite: 0.7.2
|
||||||
unpipe: 1.0.0
|
unpipe: 1.0.0
|
||||||
|
|
||||||
readable-stream@2.3.8:
|
readable-stream@2.3.8:
|
||||||
@ -755,7 +767,7 @@ snapshots:
|
|||||||
|
|
||||||
safer-buffer@2.1.2: {}
|
safer-buffer@2.1.2: {}
|
||||||
|
|
||||||
sax@1.4.3: {}
|
sax@1.6.0: {}
|
||||||
|
|
||||||
setprototypeof@1.2.0: {}
|
setprototypeof@1.2.0: {}
|
||||||
|
|
||||||
@ -789,14 +801,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
svgo@https://codeload.github.com/penpot/svgo/tar.gz/a46262c12c0d967708395972c374eb2adead4180:
|
|
||||||
dependencies:
|
|
||||||
'@trysound/sax': 0.2.0
|
|
||||||
css-select: 5.2.2
|
|
||||||
css-tree: 3.1.0
|
|
||||||
csso: 5.0.5
|
|
||||||
lodash: 4.17.21
|
|
||||||
|
|
||||||
tar-stream@3.2.0:
|
tar-stream@3.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
b4a: 1.8.1
|
b4a: 1.8.1
|
||||||
@ -835,11 +839,11 @@ snapshots:
|
|||||||
|
|
||||||
xml-js@1.6.11:
|
xml-js@1.6.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
sax: 1.4.3
|
sax: 1.6.0
|
||||||
|
|
||||||
xregexp@5.1.2:
|
xregexp@5.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime-corejs3': 7.28.4
|
'@babel/runtime-corejs3': 7.29.7
|
||||||
|
|
||||||
zip-stream@7.0.5:
|
zip-stream@7.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@ -1,2 +1,9 @@
|
|||||||
allowBuilds:
|
allowBuilds:
|
||||||
core-js-pure: false
|
core-js-pure: false
|
||||||
|
minimumReleaseAgeExclude:
|
||||||
|
- lodash@4.17.24
|
||||||
|
- lodash@4.17.23
|
||||||
|
overrides:
|
||||||
|
lodash@<=4.17.23: ^4.17.24
|
||||||
|
lodash@>=4.0.0 <=4.17.22: ^4.17.23
|
||||||
|
lodash@>=4.0.0 <=4.17.23: ^4.17.24
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
(ns app.renderer.svg
|
(ns app.renderer.svg
|
||||||
(:require
|
(:require
|
||||||
["svgo" :as svgo]
|
["@penpot/svgo" :as svgo]
|
||||||
["xml-js" :as xml]
|
["xml-js" :as xml]
|
||||||
[app.browser :as bw]
|
[app.browser :as bw]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
|||||||
@ -53,18 +53,18 @@
|
|||||||
"@penpot/draft-js": "link:packages/draft-js",
|
"@penpot/draft-js": "link:packages/draft-js",
|
||||||
"@penpot/mousetrap": "link:packages/mousetrap",
|
"@penpot/mousetrap": "link:packages/mousetrap",
|
||||||
"@penpot/plugins-runtime": "link:../plugins/libs/plugins-runtime",
|
"@penpot/plugins-runtime": "link:../plugins/libs/plugins-runtime",
|
||||||
"@penpot/svgo": "github:penpot/svgo#v3.2",
|
"@penpot/svgo": "penpot/svgo#3.3.0",
|
||||||
"@penpot/text-editor": "link:text-editor",
|
"@penpot/text-editor": "link:text-editor",
|
||||||
"@penpot/tokenscript": "link:packages/tokenscript",
|
"@penpot/tokenscript": "link:packages/tokenscript",
|
||||||
"@penpot/ui": "link:packages/ui",
|
"@penpot/ui": "link:packages/ui",
|
||||||
"@penpot/ua-parser": "penpot/ua-parser#1.0.0",
|
"@penpot/ua-parser": "penpot/ua-parser#1.0.0",
|
||||||
"@playwright/test": "1.60.0",
|
"@playwright/test": "1.60.0",
|
||||||
"@storybook/addon-docs": "10.4.3",
|
"@storybook/addon-docs": "10.4.4",
|
||||||
"@storybook/addon-themes": "10.4.3",
|
"@storybook/addon-themes": "10.4.4",
|
||||||
"@storybook/addon-vitest": "10.4.3",
|
"@storybook/addon-vitest": "10.4.4",
|
||||||
"@storybook/react-vite": "10.4.3",
|
"@storybook/react-vite": "10.4.4",
|
||||||
"@tokens-studio/sd-transforms": "2.0.3",
|
"@tokens-studio/sd-transforms": "2.0.3",
|
||||||
"@types/node": "^25.9.2",
|
"@types/node": "^25.9.3",
|
||||||
"@vitest/browser": "4.1.8",
|
"@vitest/browser": "4.1.8",
|
||||||
"@vitest/browser-playwright": "^4.1.8",
|
"@vitest/browser-playwright": "^4.1.8",
|
||||||
"@vitest/coverage-v8": "4.1.8",
|
"@vitest/coverage-v8": "4.1.8",
|
||||||
@ -73,7 +73,7 @@
|
|||||||
"compression": "^1.8.1",
|
"compression": "^1.8.1",
|
||||||
"concurrently": "^10.0.3",
|
"concurrently": "^10.0.3",
|
||||||
"date-fns": "^4.4.0",
|
"date-fns": "^4.4.0",
|
||||||
"esbuild": "^0.28.0",
|
"esbuild": "^0.28.1",
|
||||||
"eventsource-parser": "^3.1.0",
|
"eventsource-parser": "^3.1.0",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"fancy-log": "^2.0.0",
|
"fancy-log": "^2.0.0",
|
||||||
@ -112,7 +112,7 @@
|
|||||||
"sax": "^1.6.0",
|
"sax": "^1.6.0",
|
||||||
"scheduler": "^0.27.0",
|
"scheduler": "^0.27.0",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"storybook": "10.4.3",
|
"storybook": "10.4.4",
|
||||||
"style-dictionary": "5.4.4",
|
"style-dictionary": "5.4.4",
|
||||||
"stylelint": "^17.13.0",
|
"stylelint": "^17.13.0",
|
||||||
"stylelint-config-standard-scss": "^17.0.0",
|
"stylelint-config-standard-scss": "^17.0.0",
|
||||||
|
|||||||
441
frontend/pnpm-lock.yaml
generated
441
frontend/pnpm-lock.yaml
generated
@ -35,8 +35,8 @@ importers:
|
|||||||
specifier: link:../plugins/libs/plugins-runtime
|
specifier: link:../plugins/libs/plugins-runtime
|
||||||
version: link:../plugins/libs/plugins-runtime
|
version: link:../plugins/libs/plugins-runtime
|
||||||
'@penpot/svgo':
|
'@penpot/svgo':
|
||||||
specifier: github:penpot/svgo#v3.2
|
specifier: penpot/svgo#3.3.0
|
||||||
version: svgo@https://codeload.github.com/penpot/svgo/tar.gz/8c9b0e32e9cb5f106085260bd9375f3c91a5010b
|
version: https://codeload.github.com/penpot/svgo/tar.gz/65b3a645df9edbe3c00acf4267dd06c2ca736021
|
||||||
'@penpot/text-editor':
|
'@penpot/text-editor':
|
||||||
specifier: link:text-editor
|
specifier: link:text-editor
|
||||||
version: link:text-editor
|
version: link:text-editor
|
||||||
@ -53,22 +53,22 @@ importers:
|
|||||||
specifier: 1.60.0
|
specifier: 1.60.0
|
||||||
version: 1.60.0
|
version: 1.60.0
|
||||||
'@storybook/addon-docs':
|
'@storybook/addon-docs':
|
||||||
specifier: 10.4.3
|
specifier: 10.4.4
|
||||||
version: 10.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
version: 10.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
'@storybook/addon-themes':
|
'@storybook/addon-themes':
|
||||||
specifier: 10.4.3
|
specifier: 10.4.4
|
||||||
version: 10.4.3(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))
|
version: 10.4.4(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))
|
||||||
'@storybook/addon-vitest':
|
'@storybook/addon-vitest':
|
||||||
specifier: 10.4.3
|
specifier: 10.4.4
|
||||||
version: 10.4.3(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8)(@vitest/runner@4.1.8)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vitest@4.1.8)
|
version: 10.4.4(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8)(@vitest/runner@4.1.8)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vitest@4.1.8)
|
||||||
'@storybook/react-vite':
|
'@storybook/react-vite':
|
||||||
specifier: 10.4.3
|
specifier: 10.4.4
|
||||||
version: 10.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
version: 10.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
'@tokens-studio/sd-transforms':
|
'@tokens-studio/sd-transforms':
|
||||||
specifier: 2.0.3
|
specifier: 2.0.3
|
||||||
version: 2.0.3(style-dictionary@5.4.4(tslib@2.8.1))
|
version: 2.0.3(style-dictionary@5.4.4(tslib@2.8.1))
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.9.2
|
specifier: ^25.9.3
|
||||||
version: 25.9.3
|
version: 25.9.3
|
||||||
'@vitest/browser':
|
'@vitest/browser':
|
||||||
specifier: 4.1.8
|
specifier: 4.1.8
|
||||||
@ -95,14 +95,14 @@ importers:
|
|||||||
specifier: ^4.4.0
|
specifier: ^4.4.0
|
||||||
version: 4.4.0
|
version: 4.4.0
|
||||||
esbuild:
|
esbuild:
|
||||||
specifier: ^0.28.0
|
specifier: ^0.28.1
|
||||||
version: 0.28.1
|
version: 0.28.1
|
||||||
eventsource-parser:
|
eventsource-parser:
|
||||||
specifier: ^3.1.0
|
specifier: ^3.1.0
|
||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
express:
|
express:
|
||||||
specifier: ^5.1.0
|
specifier: ^5.1.0
|
||||||
version: 5.2.1
|
version: 5.2.1(supports-color@5.5.0)
|
||||||
fancy-log:
|
fancy-log:
|
||||||
specifier: ^2.0.0
|
specifier: ^2.0.0
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
@ -212,23 +212,23 @@ importers:
|
|||||||
specifier: ^0.5.21
|
specifier: ^0.5.21
|
||||||
version: 0.5.21
|
version: 0.5.21
|
||||||
storybook:
|
storybook:
|
||||||
specifier: 10.4.3
|
specifier: 10.4.4
|
||||||
version: 10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
version: 10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
style-dictionary:
|
style-dictionary:
|
||||||
specifier: 5.4.4
|
specifier: 5.4.4
|
||||||
version: 5.4.4(tslib@2.8.1)
|
version: 5.4.4(tslib@2.8.1)
|
||||||
stylelint:
|
stylelint:
|
||||||
specifier: ^17.13.0
|
specifier: ^17.13.0
|
||||||
version: 17.13.0(typescript@6.0.3)
|
version: 17.13.0(supports-color@5.5.0)(typescript@6.0.3)
|
||||||
stylelint-config-standard-scss:
|
stylelint-config-standard-scss:
|
||||||
specifier: ^17.0.0
|
specifier: ^17.0.0
|
||||||
version: 17.0.0(postcss@8.5.15)(stylelint@17.13.0(typescript@6.0.3))
|
version: 17.0.0(postcss@8.5.15)(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3))
|
||||||
stylelint-scss:
|
stylelint-scss:
|
||||||
specifier: ^7.2.0
|
specifier: ^7.2.0
|
||||||
version: 7.2.0(stylelint@17.13.0(typescript@6.0.3))
|
version: 7.2.0(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3))
|
||||||
stylelint-use-logical-spec:
|
stylelint-use-logical-spec:
|
||||||
specifier: ^5.0.1
|
specifier: ^5.0.1
|
||||||
version: 5.0.1(stylelint@17.13.0(typescript@6.0.3))
|
version: 5.0.1(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3))
|
||||||
svg-sprite:
|
svg-sprite:
|
||||||
specifier: ^2.0.4
|
specifier: ^2.0.4
|
||||||
version: 2.0.4
|
version: 2.0.4
|
||||||
@ -249,7 +249,7 @@ importers:
|
|||||||
version: 4.1.8(@types/node@25.9.3)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-v8@4.1.8)(@vitest/ui@4.1.8)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
version: 4.1.8(@types/node@25.9.3)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-v8@4.1.8)(@vitest/ui@4.1.8)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
wait-on:
|
wait-on:
|
||||||
specifier: ^9.0.4
|
specifier: ^9.0.4
|
||||||
version: 9.0.10
|
version: 9.0.10(supports-color@5.5.0)
|
||||||
watcher:
|
watcher:
|
||||||
specifier: ^2.3.1
|
specifier: ^2.3.1
|
||||||
version: 2.3.1
|
version: 2.3.1
|
||||||
@ -346,7 +346,7 @@ importers:
|
|||||||
version: 10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
version: 10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
vite-plugin-dts:
|
vite-plugin-dts:
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.0.2(esbuild@0.28.1)(rolldown@1.0.3)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
version: 5.0.2(esbuild@0.28.1)(rolldown@1.0.3)(supports-color@5.5.0)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
|
|
||||||
text-editor:
|
text-editor:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@ -1549,6 +1549,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
|
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
|
|
||||||
|
'@penpot/svgo@https://codeload.github.com/penpot/svgo/tar.gz/65b3a645df9edbe3c00acf4267dd06c2ca736021':
|
||||||
|
resolution: {gitHosted: true, tarball: https://codeload.github.com/penpot/svgo/tar.gz/65b3a645df9edbe3c00acf4267dd06c2ca736021}
|
||||||
|
version: 3.3.0
|
||||||
|
|
||||||
'@penpot/ua-parser@https://codeload.github.com/penpot/ua-parser/tar.gz/90b970f39f2dc08378b975a0f01045b4ec8e89a4':
|
'@penpot/ua-parser@https://codeload.github.com/penpot/ua-parser/tar.gz/90b970f39f2dc08378b975a0f01045b4ec8e89a4':
|
||||||
resolution: {gitHosted: true, integrity: sha512-BxcjiWGtCbGBT+dsOnEODk1jASZLNYp27BuGQaJR7fxU4gLws3251r90Sp9seubcpRhGrfRdsA5WU0ExRdPOgg==, tarball: https://codeload.github.com/penpot/ua-parser/tar.gz/90b970f39f2dc08378b975a0f01045b4ec8e89a4}
|
resolution: {gitHosted: true, integrity: sha512-BxcjiWGtCbGBT+dsOnEODk1jASZLNYp27BuGQaJR7fxU4gLws3251r90Sp9seubcpRhGrfRdsA5WU0ExRdPOgg==, tarball: https://codeload.github.com/penpot/ua-parser/tar.gz/90b970f39f2dc08378b975a0f01045b4ec8e89a4}
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
@ -1765,27 +1769,27 @@ packages:
|
|||||||
'@standard-schema/spec@1.1.0':
|
'@standard-schema/spec@1.1.0':
|
||||||
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
|
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
|
||||||
|
|
||||||
'@storybook/addon-docs@10.4.3':
|
'@storybook/addon-docs@10.4.4':
|
||||||
resolution: {integrity: sha512-CJGEXSo0zpIy7gvEeeUi09ZbjQUSNDi4YipAeb+lZGGEn8ShZUr2Pk330yd2ZO+ngNWJXD4ZxOb0e3/aIlxb3Q==}
|
resolution: {integrity: sha512-yPshCvtmQTq52T2sXuXgjy7B/QbhA/WIZxLYggptNjBL8BJMvbOfp9bAfCKh7+KpRWGqDZ6Y6tWL1Q48Wj3vtw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
storybook: ^10.4.3
|
storybook: ^10.4.4
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@storybook/addon-themes@10.4.3':
|
'@storybook/addon-themes@10.4.4':
|
||||||
resolution: {integrity: sha512-pL73C5h6uyIpeLXjptefjo52Kjhq6ZQh+XgTs8b93ytYy5fkupvQeoGjUnMknTjoIabNPSOhvb0Mcj5OUA+XCw==}
|
resolution: {integrity: sha512-VH443z7o/JO5K9QFVuB9IzwaMu0jEiq4ybpzTlAmt0ZUEqNBuM+ESBvkVMkZ5QeNghKrs/J9yvum2g2t94YR4Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
storybook: ^10.4.3
|
storybook: ^10.4.4
|
||||||
|
|
||||||
'@storybook/addon-vitest@10.4.3':
|
'@storybook/addon-vitest@10.4.4':
|
||||||
resolution: {integrity: sha512-np5qbyc/A7bZTvRlap9eaNmp9ix9yBBhMc3ClF4u2NkyI9MNLRH2xh66mI9lsShTyUZ6NAD8Uj72YJXkcigP6w==}
|
resolution: {integrity: sha512-VPpBwf1Elr+0g33am8ZE6aHhLB+r1TPxUsnDuCVNhxGjRxMFyQkAE8+jPJFPvS/YIUGMbVXarzaV7PcI/sJuVQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@vitest/browser': ^3.0.0 || ^4.0.0
|
'@vitest/browser': ^3.0.0 || ^4.0.0
|
||||||
'@vitest/browser-playwright': ^4.0.0
|
'@vitest/browser-playwright': ^4.0.0
|
||||||
'@vitest/runner': ^3.0.0 || ^4.0.0
|
'@vitest/runner': ^3.0.0 || ^4.0.0
|
||||||
storybook: ^10.4.3
|
storybook: ^10.4.4
|
||||||
vitest: ^3.0.0 || ^4.0.0
|
vitest: ^3.0.0 || ^4.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
'@vitest/browser':
|
'@vitest/browser':
|
||||||
@ -1803,6 +1807,12 @@ packages:
|
|||||||
storybook: ^10.4.3
|
storybook: ^10.4.3
|
||||||
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
|
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||||
|
|
||||||
|
'@storybook/builder-vite@10.4.4':
|
||||||
|
resolution: {integrity: sha512-VyuZ4mEvhhVXjJa1qXMWKH8ohnas0rgEuJDf6u4aJ54XeENFebPUEAHde1Qo2PflJ4rUdVdXieOZzKbYwP5RAQ==}
|
||||||
|
peerDependencies:
|
||||||
|
storybook: ^10.4.4
|
||||||
|
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||||
|
|
||||||
'@storybook/csf-plugin@10.4.3':
|
'@storybook/csf-plugin@10.4.3':
|
||||||
resolution: {integrity: sha512-D+XF5CVhZmIOI0uhfTKxlQr+gR1z8X9djPy9phiA1USLPAOHagBAucp/PhLwlFVUxrKzEIf8yImrvkCv50IcDg==}
|
resolution: {integrity: sha512-D+XF5CVhZmIOI0uhfTKxlQr+gR1z8X9djPy9phiA1USLPAOHagBAucp/PhLwlFVUxrKzEIf8yImrvkCv50IcDg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1821,6 +1831,24 @@ packages:
|
|||||||
webpack:
|
webpack:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@storybook/csf-plugin@10.4.4':
|
||||||
|
resolution: {integrity: sha512-1mzZyAwVUmAcw4WEUsJDVdSupkJf+Kf/f5uNAs4RzlBXA75P8YRkDKAb2EoMwsB5URiXFi9XoeAN/vWke0G6+w==}
|
||||||
|
peerDependencies:
|
||||||
|
esbuild: '*'
|
||||||
|
rollup: '*'
|
||||||
|
storybook: ^10.4.4
|
||||||
|
vite: '*'
|
||||||
|
webpack: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
esbuild:
|
||||||
|
optional: true
|
||||||
|
rollup:
|
||||||
|
optional: true
|
||||||
|
vite:
|
||||||
|
optional: true
|
||||||
|
webpack:
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@storybook/global@5.0.0':
|
'@storybook/global@5.0.0':
|
||||||
resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==}
|
resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==}
|
||||||
|
|
||||||
@ -1844,6 +1872,20 @@ packages:
|
|||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@storybook/react-dom-shim@10.4.4':
|
||||||
|
resolution: {integrity: sha512-y6SObmoW78AydE6VfKQSUmCkuqiaMPy9LgMpMdMEyWfJ/pSxBDMIKycr9dlRMJP1cvNgByaJgrusWtA46ndSQw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
'@types/react-dom': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
storybook: ^10.4.4
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@storybook/react-vite@10.4.3':
|
'@storybook/react-vite@10.4.3':
|
||||||
resolution: {integrity: sha512-Pk/hi10JFuwJ5sj/HAapWrgaa9Z83oT4MJPbHqeKzMt3A3jkIru4L9ibnt82bzV3crOaiErprvOlAFDsjxhrrQ==}
|
resolution: {integrity: sha512-Pk/hi10JFuwJ5sj/HAapWrgaa9Z83oT4MJPbHqeKzMt3A3jkIru4L9ibnt82bzV3crOaiErprvOlAFDsjxhrrQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1852,6 +1894,14 @@ packages:
|
|||||||
storybook: ^10.4.3
|
storybook: ^10.4.3
|
||||||
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
|
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||||
|
|
||||||
|
'@storybook/react-vite@10.4.4':
|
||||||
|
resolution: {integrity: sha512-hXw1c9Jq2eFzwmJ3u9phmszbHoPjwPLYjcR1Grd6Xbe2g3bReGH35urm/fTZ0HNdjXAgQlUaXp2bWw6vz0BHQw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
storybook: ^10.4.4
|
||||||
|
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||||
|
|
||||||
'@storybook/react@10.4.3':
|
'@storybook/react@10.4.3':
|
||||||
resolution: {integrity: sha512-Td+Zoi8ylJTPC1jg5vHw8OK7U2kJgqc5kuAn92UvD4IbAkcpMTBRPHDziK1piv6q7r8yNLVah+ku6IKHpTLeXA==}
|
resolution: {integrity: sha512-Td+Zoi8ylJTPC1jg5vHw8OK7U2kJgqc5kuAn92UvD4IbAkcpMTBRPHDziK1piv6q7r8yNLVah+ku6IKHpTLeXA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1869,6 +1919,23 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@storybook/react@10.4.4':
|
||||||
|
resolution: {integrity: sha512-6K5/uHrvjswrueyVpUt6IWGuSgYCMtMOYyVs86XJZYqKBV3Pv7nGsGNH7YSMLAVQBZW4CQqm2etd5Op0GHY9Kg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
'@types/react-dom': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
storybook: ^10.4.4
|
||||||
|
typescript: '>= 4.9.x'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@testing-library/dom@10.4.1':
|
'@testing-library/dom@10.4.1':
|
||||||
resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
|
resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -1912,10 +1979,6 @@ packages:
|
|||||||
'@tokens-studio/types@0.5.2':
|
'@tokens-studio/types@0.5.2':
|
||||||
resolution: {integrity: sha512-rzMcZP0bj2E5jaa7Fj0LGgYHysoCrbrxILVbT0ohsCUH5uCHY/u6J7Qw/TE0n6gR9Js/c9ZO9T8mOoz0HdLMbA==}
|
resolution: {integrity: sha512-rzMcZP0bj2E5jaa7Fj0LGgYHysoCrbrxILVbT0ohsCUH5uCHY/u6J7Qw/TE0n6gR9Js/c9ZO9T8mOoz0HdLMbA==}
|
||||||
|
|
||||||
'@trysound/sax@0.2.0':
|
|
||||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
|
||||||
engines: {node: '>=10.13.0'}
|
|
||||||
|
|
||||||
'@tybys/wasm-util@0.10.2':
|
'@tybys/wasm-util@0.10.2':
|
||||||
resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
|
resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
|
||||||
|
|
||||||
@ -2269,6 +2332,10 @@ packages:
|
|||||||
boolbase@1.0.0:
|
boolbase@1.0.0:
|
||||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||||
|
|
||||||
|
boolbase@2.0.0:
|
||||||
|
resolution: {integrity: sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
brace-expansion@1.1.15:
|
brace-expansion@1.1.15:
|
||||||
resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==}
|
resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==}
|
||||||
|
|
||||||
@ -2546,8 +2613,9 @@ packages:
|
|||||||
css-select@4.3.0:
|
css-select@4.3.0:
|
||||||
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
|
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
|
||||||
|
|
||||||
css-select@5.2.2:
|
css-select@7.0.0:
|
||||||
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
|
resolution: {integrity: sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
css-selector-parser@1.4.1:
|
css-selector-parser@1.4.1:
|
||||||
resolution: {integrity: sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==}
|
resolution: {integrity: sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==}
|
||||||
@ -2568,6 +2636,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
|
resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
css-what@8.0.0:
|
||||||
|
resolution: {integrity: sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
css.escape@1.5.1:
|
css.escape@1.5.1:
|
||||||
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
|
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
|
||||||
|
|
||||||
@ -2718,25 +2790,31 @@ packages:
|
|||||||
dom-serializer@1.4.1:
|
dom-serializer@1.4.1:
|
||||||
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
|
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
|
||||||
|
|
||||||
dom-serializer@2.0.0:
|
dom-serializer@3.1.1:
|
||||||
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
resolution: {integrity: sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
domelementtype@2.3.0:
|
domelementtype@2.3.0:
|
||||||
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||||
|
|
||||||
|
domelementtype@3.0.0:
|
||||||
|
resolution: {integrity: sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
domhandler@4.3.1:
|
domhandler@4.3.1:
|
||||||
resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
|
resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
domhandler@5.0.3:
|
domhandler@6.0.1:
|
||||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
resolution: {integrity: sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
domutils@2.8.0:
|
domutils@2.8.0:
|
||||||
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
|
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
|
||||||
|
|
||||||
domutils@3.2.2:
|
domutils@4.0.2:
|
||||||
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
resolution: {integrity: sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
draft-js@https://codeload.github.com/penpot/draft-js/tar.gz/4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0:
|
draft-js@https://codeload.github.com/penpot/draft-js/tar.gz/4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0:
|
||||||
resolution: {gitHosted: true, tarball: https://codeload.github.com/penpot/draft-js/tar.gz/4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0}
|
resolution: {gitHosted: true, tarball: https://codeload.github.com/penpot/draft-js/tar.gz/4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0}
|
||||||
@ -2792,10 +2870,6 @@ packages:
|
|||||||
entities@2.2.0:
|
entities@2.2.0:
|
||||||
resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
|
resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
|
||||||
|
|
||||||
entities@4.5.0:
|
|
||||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
|
||||||
engines: {node: '>=0.12'}
|
|
||||||
|
|
||||||
entities@8.0.0:
|
entities@8.0.0:
|
||||||
resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==}
|
resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==}
|
||||||
engines: {node: '>=20.19.0'}
|
engines: {node: '>=20.19.0'}
|
||||||
@ -4015,6 +4089,10 @@ packages:
|
|||||||
nth-check@2.1.1:
|
nth-check@2.1.1:
|
||||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||||
|
|
||||||
|
nth-check@3.0.1:
|
||||||
|
resolution: {integrity: sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
object-assign@4.1.1:
|
object-assign@4.1.1:
|
||||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -4858,6 +4936,21 @@ packages:
|
|||||||
vite-plus:
|
vite-plus:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
storybook@10.4.4:
|
||||||
|
resolution: {integrity: sha512-Nn0qFRxU5fyABa6dGRftfL3lz0Y+HkKOaAkfytF8S4Q2K6Szwwq7TwPAEs3Wsj8hBQbYhsobrKADcPsyXQpJaA==}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
prettier: ^2 || ^3
|
||||||
|
vite-plus: ^0.1.15
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
prettier:
|
||||||
|
optional: true
|
||||||
|
vite-plus:
|
||||||
|
optional: true
|
||||||
|
|
||||||
stream@0.0.3:
|
stream@0.0.3:
|
||||||
resolution: {integrity: sha512-aMsbn7VKrl4A2T7QAQQbzgN7NVc70vgF5INQrBXqn4dCXN1zy3L9HGgLO5s7PExmdrzTJ8uR/27aviW8or8/+A==}
|
resolution: {integrity: sha512-aMsbn7VKrl4A2T7QAQQbzgN7NVc70vgF5INQrBXqn4dCXN1zy3L9HGgLO5s7PExmdrzTJ8uR/27aviW8or8/+A==}
|
||||||
|
|
||||||
@ -5035,11 +5128,6 @@ packages:
|
|||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
svgo@https://codeload.github.com/penpot/svgo/tar.gz/8c9b0e32e9cb5f106085260bd9375f3c91a5010b:
|
|
||||||
resolution: {gitHosted: true, tarball: https://codeload.github.com/penpot/svgo/tar.gz/8c9b0e32e9cb5f106085260bd9375f3c91a5010b}
|
|
||||||
version: 4.0.0
|
|
||||||
engines: {node: '>=16.0.0'}
|
|
||||||
|
|
||||||
symbol-tree@3.2.4:
|
symbol-tree@3.2.4:
|
||||||
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
|
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
|
||||||
|
|
||||||
@ -6519,6 +6607,14 @@ snapshots:
|
|||||||
'@parcel/watcher-win32-x64': 2.5.6
|
'@parcel/watcher-win32-x64': 2.5.6
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@penpot/svgo@https://codeload.github.com/penpot/svgo/tar.gz/65b3a645df9edbe3c00acf4267dd06c2ca736021':
|
||||||
|
dependencies:
|
||||||
|
css-select: 7.0.0
|
||||||
|
css-tree: 3.2.1
|
||||||
|
csso: 5.0.5
|
||||||
|
lodash: 4.18.1
|
||||||
|
sax: 1.6.0
|
||||||
|
|
||||||
'@penpot/ua-parser@https://codeload.github.com/penpot/ua-parser/tar.gz/90b970f39f2dc08378b975a0f01045b4ec8e89a4': {}
|
'@penpot/ua-parser@https://codeload.github.com/penpot/ua-parser/tar.gz/90b970f39f2dc08378b975a0f01045b4ec8e89a4': {}
|
||||||
|
|
||||||
'@pkgjs/parseargs@0.11.0':
|
'@pkgjs/parseargs@0.11.0':
|
||||||
@ -6649,15 +6745,15 @@ snapshots:
|
|||||||
|
|
||||||
'@standard-schema/spec@1.1.0': {}
|
'@standard-schema/spec@1.1.0': {}
|
||||||
|
|
||||||
'@storybook/addon-docs@10.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))':
|
'@storybook/addon-docs@10.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7)
|
'@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7)
|
||||||
'@storybook/csf-plugin': 10.4.3(esbuild@0.28.1)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
'@storybook/csf-plugin': 10.4.4(esbuild@0.28.1)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
'@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
'@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
'@storybook/react-dom-shim': 10.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))
|
'@storybook/react-dom-shim': 10.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))
|
||||||
react: 19.2.7
|
react: 19.2.7
|
||||||
react-dom: 19.2.7(react@19.2.7)
|
react-dom: 19.2.7(react@19.2.7)
|
||||||
storybook: 10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
storybook: 10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
ts-dedent: 2.3.0
|
ts-dedent: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 19.2.17
|
'@types/react': 19.2.17
|
||||||
@ -6668,16 +6764,16 @@ snapshots:
|
|||||||
- vite
|
- vite
|
||||||
- webpack
|
- webpack
|
||||||
|
|
||||||
'@storybook/addon-themes@10.4.3(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))':
|
'@storybook/addon-themes@10.4.4(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))':
|
||||||
dependencies:
|
dependencies:
|
||||||
storybook: 10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
storybook: 10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
ts-dedent: 2.3.0
|
ts-dedent: 2.3.0
|
||||||
|
|
||||||
'@storybook/addon-vitest@10.4.3(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8)(@vitest/runner@4.1.8)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vitest@4.1.8)':
|
'@storybook/addon-vitest@10.4.4(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8)(@vitest/runner@4.1.8)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vitest@4.1.8)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@storybook/global': 5.0.0
|
'@storybook/global': 5.0.0
|
||||||
'@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
'@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
storybook: 10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
storybook: 10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@vitest/browser': 4.1.8(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))(vitest@4.1.8)
|
'@vitest/browser': 4.1.8(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))(vitest@4.1.8)
|
||||||
'@vitest/browser-playwright': 4.1.8(playwright@1.60.0)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))(vitest@4.1.8)
|
'@vitest/browser-playwright': 4.1.8(playwright@1.60.0)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))(vitest@4.1.8)
|
||||||
@ -6698,6 +6794,17 @@ snapshots:
|
|||||||
- rollup
|
- rollup
|
||||||
- webpack
|
- webpack
|
||||||
|
|
||||||
|
'@storybook/builder-vite@10.4.4(esbuild@0.28.1)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))':
|
||||||
|
dependencies:
|
||||||
|
'@storybook/csf-plugin': 10.4.4(esbuild@0.28.1)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
|
storybook: 10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
|
ts-dedent: 2.3.0
|
||||||
|
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- esbuild
|
||||||
|
- rollup
|
||||||
|
- webpack
|
||||||
|
|
||||||
'@storybook/csf-plugin@10.4.3(esbuild@0.28.1)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))':
|
'@storybook/csf-plugin@10.4.3(esbuild@0.28.1)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
storybook: 10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
storybook: 10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
@ -6706,6 +6813,14 @@ snapshots:
|
|||||||
esbuild: 0.28.1
|
esbuild: 0.28.1
|
||||||
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)
|
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)
|
||||||
|
|
||||||
|
'@storybook/csf-plugin@10.4.4(esbuild@0.28.1)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))':
|
||||||
|
dependencies:
|
||||||
|
storybook: 10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
|
unplugin: 2.3.11
|
||||||
|
optionalDependencies:
|
||||||
|
esbuild: 0.28.1
|
||||||
|
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)
|
||||||
|
|
||||||
'@storybook/global@5.0.0': {}
|
'@storybook/global@5.0.0': {}
|
||||||
|
|
||||||
'@storybook/icons@2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)':
|
'@storybook/icons@2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)':
|
||||||
@ -6722,6 +6837,15 @@ snapshots:
|
|||||||
'@types/react': 19.2.17
|
'@types/react': 19.2.17
|
||||||
'@types/react-dom': 19.2.3(@types/react@19.2.17)
|
'@types/react-dom': 19.2.3(@types/react@19.2.17)
|
||||||
|
|
||||||
|
'@storybook/react-dom-shim@10.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))':
|
||||||
|
dependencies:
|
||||||
|
react: 19.2.7
|
||||||
|
react-dom: 19.2.7(react@19.2.7)
|
||||||
|
storybook: 10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.2.17
|
||||||
|
'@types/react-dom': 19.2.3(@types/react@19.2.17)
|
||||||
|
|
||||||
'@storybook/react-vite@10.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))':
|
'@storybook/react-vite@10.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
'@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
@ -6746,6 +6870,30 @@ snapshots:
|
|||||||
- typescript
|
- typescript
|
||||||
- webpack
|
- webpack
|
||||||
|
|
||||||
|
'@storybook/react-vite@10.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))':
|
||||||
|
dependencies:
|
||||||
|
'@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
|
'@rollup/pluginutils': 5.4.0
|
||||||
|
'@storybook/builder-vite': 10.4.4(esbuild@0.28.1)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
|
'@storybook/react': 10.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)
|
||||||
|
empathic: 2.0.1
|
||||||
|
magic-string: 0.30.21
|
||||||
|
react: 19.2.7
|
||||||
|
react-docgen: 8.0.3
|
||||||
|
react-dom: 19.2.7(react@19.2.7)
|
||||||
|
resolve: 1.22.12
|
||||||
|
storybook: 10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
|
tsconfig-paths: 4.2.0
|
||||||
|
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/react'
|
||||||
|
- '@types/react-dom'
|
||||||
|
- esbuild
|
||||||
|
- rollup
|
||||||
|
- supports-color
|
||||||
|
- typescript
|
||||||
|
- webpack
|
||||||
|
|
||||||
'@storybook/react@10.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)':
|
'@storybook/react@10.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.3(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@storybook/global': 5.0.0
|
'@storybook/global': 5.0.0
|
||||||
@ -6762,6 +6910,22 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@storybook/react@10.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)':
|
||||||
|
dependencies:
|
||||||
|
'@storybook/global': 5.0.0
|
||||||
|
'@storybook/react-dom-shim': 10.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))
|
||||||
|
react: 19.2.7
|
||||||
|
react-docgen: 8.0.3
|
||||||
|
react-docgen-typescript: 2.4.0(typescript@6.0.3)
|
||||||
|
react-dom: 19.2.7(react@19.2.7)
|
||||||
|
storybook: 10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.2.17
|
||||||
|
'@types/react-dom': 19.2.3(@types/react@19.2.17)
|
||||||
|
typescript: 6.0.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
'@testing-library/dom@10.4.1':
|
'@testing-library/dom@10.4.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/code-frame': 7.29.7
|
'@babel/code-frame': 7.29.7
|
||||||
@ -6815,8 +6979,6 @@ snapshots:
|
|||||||
|
|
||||||
'@tokens-studio/types@0.5.2': {}
|
'@tokens-studio/types@0.5.2': {}
|
||||||
|
|
||||||
'@trysound/sax@0.2.0': {}
|
|
||||||
|
|
||||||
'@tybys/wasm-util@0.10.2':
|
'@tybys/wasm-util@0.10.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
@ -7036,7 +7198,7 @@ snapshots:
|
|||||||
|
|
||||||
acorn@8.17.0: {}
|
acorn@8.17.0: {}
|
||||||
|
|
||||||
agent-base@6.0.2:
|
agent-base@6.0.2(supports-color@5.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3(supports-color@5.5.0)
|
debug: 4.4.3(supports-color@5.5.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -7209,11 +7371,11 @@ snapshots:
|
|||||||
|
|
||||||
axe-core@4.12.1: {}
|
axe-core@4.12.1: {}
|
||||||
|
|
||||||
axios@1.17.0:
|
axios@1.17.0(supports-color@5.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.16.0
|
follow-redirects: 1.16.0
|
||||||
form-data: 4.0.5
|
form-data: 4.0.5
|
||||||
https-proxy-agent: 5.0.1
|
https-proxy-agent: 5.0.1(supports-color@5.5.0)
|
||||||
proxy-from-env: 2.1.0
|
proxy-from-env: 2.1.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- debug
|
- debug
|
||||||
@ -7247,7 +7409,7 @@ snapshots:
|
|||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
|
|
||||||
body-parser@2.2.2:
|
body-parser@2.2.2(supports-color@5.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
bytes: 3.1.2
|
bytes: 3.1.2
|
||||||
content-type: 1.0.5
|
content-type: 1.0.5
|
||||||
@ -7263,6 +7425,8 @@ snapshots:
|
|||||||
|
|
||||||
boolbase@1.0.0: {}
|
boolbase@1.0.0: {}
|
||||||
|
|
||||||
|
boolbase@2.0.0: {}
|
||||||
|
|
||||||
brace-expansion@1.1.15:
|
brace-expansion@1.1.15:
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match: 1.0.2
|
balanced-match: 1.0.2
|
||||||
@ -7555,13 +7719,13 @@ snapshots:
|
|||||||
domutils: 2.8.0
|
domutils: 2.8.0
|
||||||
nth-check: 2.1.1
|
nth-check: 2.1.1
|
||||||
|
|
||||||
css-select@5.2.2:
|
css-select@7.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 2.0.0
|
||||||
css-what: 6.2.2
|
css-what: 8.0.0
|
||||||
domhandler: 5.0.3
|
domhandler: 6.0.1
|
||||||
domutils: 3.2.2
|
domutils: 4.0.2
|
||||||
nth-check: 2.1.1
|
nth-check: 3.0.1
|
||||||
|
|
||||||
css-selector-parser@1.4.1: {}
|
css-selector-parser@1.4.1: {}
|
||||||
|
|
||||||
@ -7582,6 +7746,8 @@ snapshots:
|
|||||||
|
|
||||||
css-what@6.2.2: {}
|
css-what@6.2.2: {}
|
||||||
|
|
||||||
|
css-what@8.0.0: {}
|
||||||
|
|
||||||
css.escape@1.5.1: {}
|
css.escape@1.5.1: {}
|
||||||
|
|
||||||
cssesc@3.0.0: {}
|
cssesc@3.0.0: {}
|
||||||
@ -7709,21 +7875,23 @@ snapshots:
|
|||||||
domhandler: 4.3.1
|
domhandler: 4.3.1
|
||||||
entities: 2.2.0
|
entities: 2.2.0
|
||||||
|
|
||||||
dom-serializer@2.0.0:
|
dom-serializer@3.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 3.0.0
|
||||||
domhandler: 5.0.3
|
domhandler: 6.0.1
|
||||||
entities: 4.5.0
|
entities: 8.0.0
|
||||||
|
|
||||||
domelementtype@2.3.0: {}
|
domelementtype@2.3.0: {}
|
||||||
|
|
||||||
|
domelementtype@3.0.0: {}
|
||||||
|
|
||||||
domhandler@4.3.1:
|
domhandler@4.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
|
|
||||||
domhandler@5.0.3:
|
domhandler@6.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 3.0.0
|
||||||
|
|
||||||
domutils@2.8.0:
|
domutils@2.8.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -7731,11 +7899,11 @@ snapshots:
|
|||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
domhandler: 4.3.1
|
domhandler: 4.3.1
|
||||||
|
|
||||||
domutils@3.2.2:
|
domutils@4.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
dom-serializer: 2.0.0
|
dom-serializer: 3.1.1
|
||||||
domelementtype: 2.3.0
|
domelementtype: 3.0.0
|
||||||
domhandler: 5.0.3
|
domhandler: 6.0.1
|
||||||
|
|
||||||
draft-js@https://codeload.github.com/penpot/draft-js/tar.gz/4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0(encoding@0.1.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
draft-js@https://codeload.github.com/penpot/draft-js/tar.gz/4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0(encoding@0.1.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -7788,8 +7956,6 @@ snapshots:
|
|||||||
|
|
||||||
entities@2.2.0: {}
|
entities@2.2.0: {}
|
||||||
|
|
||||||
entities@4.5.0: {}
|
|
||||||
|
|
||||||
entities@8.0.0: {}
|
entities@8.0.0: {}
|
||||||
|
|
||||||
env-paths@2.2.1: {}
|
env-paths@2.2.1: {}
|
||||||
@ -8149,10 +8315,10 @@ snapshots:
|
|||||||
|
|
||||||
expr-eval-fork@3.0.3: {}
|
expr-eval-fork@3.0.3: {}
|
||||||
|
|
||||||
express@5.2.1:
|
express@5.2.1(supports-color@5.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
accepts: 2.0.0
|
accepts: 2.0.0
|
||||||
body-parser: 2.2.2
|
body-parser: 2.2.2(supports-color@5.5.0)
|
||||||
content-disposition: 1.1.0
|
content-disposition: 1.1.0
|
||||||
content-type: 1.0.5
|
content-type: 1.0.5
|
||||||
cookie: 0.7.2
|
cookie: 0.7.2
|
||||||
@ -8162,7 +8328,7 @@ snapshots:
|
|||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
etag: 1.8.1
|
etag: 1.8.1
|
||||||
finalhandler: 2.1.1
|
finalhandler: 2.1.1(supports-color@5.5.0)
|
||||||
fresh: 2.0.0
|
fresh: 2.0.0
|
||||||
http-errors: 2.0.1
|
http-errors: 2.0.1
|
||||||
merge-descriptors: 2.0.0
|
merge-descriptors: 2.0.0
|
||||||
@ -8173,8 +8339,8 @@ snapshots:
|
|||||||
proxy-addr: 2.0.7
|
proxy-addr: 2.0.7
|
||||||
qs: 6.15.2
|
qs: 6.15.2
|
||||||
range-parser: 1.2.1
|
range-parser: 1.2.1
|
||||||
router: 2.2.0
|
router: 2.2.0(supports-color@5.5.0)
|
||||||
send: 1.2.1
|
send: 1.2.1(supports-color@5.5.0)
|
||||||
serve-static: 2.2.1
|
serve-static: 2.2.1
|
||||||
statuses: 2.0.2
|
statuses: 2.0.2
|
||||||
type-is: 2.1.0
|
type-is: 2.1.0
|
||||||
@ -8244,7 +8410,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
|
|
||||||
finalhandler@2.1.1:
|
finalhandler@2.1.1(supports-color@5.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3(supports-color@5.5.0)
|
debug: 4.4.3(supports-color@5.5.0)
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
@ -8501,9 +8667,9 @@ snapshots:
|
|||||||
statuses: 2.0.2
|
statuses: 2.0.2
|
||||||
toidentifier: 1.0.1
|
toidentifier: 1.0.1
|
||||||
|
|
||||||
https-proxy-agent@5.0.1:
|
https-proxy-agent@5.0.1(supports-color@5.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 6.0.2
|
agent-base: 6.0.2(supports-color@5.5.0)
|
||||||
debug: 4.4.3(supports-color@5.5.0)
|
debug: 4.4.3(supports-color@5.5.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -9155,6 +9321,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 1.0.0
|
||||||
|
|
||||||
|
nth-check@3.0.1:
|
||||||
|
dependencies:
|
||||||
|
boolbase: 2.0.0
|
||||||
|
|
||||||
object-assign@4.1.1: {}
|
object-assign@4.1.1: {}
|
||||||
|
|
||||||
object-inspect@1.13.4: {}
|
object-inspect@1.13.4: {}
|
||||||
@ -9736,7 +9906,7 @@ snapshots:
|
|||||||
'@rolldown/binding-win32-arm64-msvc': 1.0.3
|
'@rolldown/binding-win32-arm64-msvc': 1.0.3
|
||||||
'@rolldown/binding-win32-x64-msvc': 1.0.3
|
'@rolldown/binding-win32-x64-msvc': 1.0.3
|
||||||
|
|
||||||
router@2.2.0:
|
router@2.2.0(supports-color@5.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3(supports-color@5.5.0)
|
debug: 4.4.3(supports-color@5.5.0)
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
@ -9903,7 +10073,7 @@ snapshots:
|
|||||||
|
|
||||||
semver@7.8.4: {}
|
semver@7.8.4: {}
|
||||||
|
|
||||||
send@1.2.1:
|
send@1.2.1(supports-color@5.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3(supports-color@5.5.0)
|
debug: 4.4.3(supports-color@5.5.0)
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
@ -9924,7 +10094,7 @@ snapshots:
|
|||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
parseurl: 1.3.3
|
parseurl: 1.3.3
|
||||||
send: 1.2.1
|
send: 1.2.1(supports-color@5.5.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@ -10091,6 +10261,33 @@ snapshots:
|
|||||||
- react-dom
|
- react-dom
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
|
storybook@10.4.4(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||||
|
dependencies:
|
||||||
|
'@storybook/global': 5.0.0
|
||||||
|
'@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
|
'@testing-library/jest-dom': 6.9.1
|
||||||
|
'@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1)
|
||||||
|
'@vitest/expect': 3.2.4
|
||||||
|
'@vitest/spy': 3.2.4
|
||||||
|
'@webcontainer/env': 1.1.1
|
||||||
|
esbuild: 0.27.7
|
||||||
|
open: 10.2.0
|
||||||
|
oxc-parser: 0.127.0
|
||||||
|
oxc-resolver: 11.20.0
|
||||||
|
recast: 0.23.11
|
||||||
|
semver: 7.8.4
|
||||||
|
use-sync-external-store: 1.6.0(react@19.2.7)
|
||||||
|
ws: 8.21.0
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.2.17
|
||||||
|
prettier: 3.8.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@testing-library/dom'
|
||||||
|
- bufferutil
|
||||||
|
- react
|
||||||
|
- react-dom
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
stream@0.0.3:
|
stream@0.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
component-emitter: 2.0.0
|
component-emitter: 2.0.0
|
||||||
@ -10226,33 +10423,33 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- tslib
|
- tslib
|
||||||
|
|
||||||
stylelint-config-recommended-scss@17.0.1(postcss@8.5.15)(stylelint@17.13.0(typescript@6.0.3)):
|
stylelint-config-recommended-scss@17.0.1(postcss@8.5.15)(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss-scss: 4.0.9(postcss@8.5.15)
|
postcss-scss: 4.0.9(postcss@8.5.15)
|
||||||
stylelint: 17.13.0(typescript@6.0.3)
|
stylelint: 17.13.0(supports-color@5.5.0)(typescript@6.0.3)
|
||||||
stylelint-config-recommended: 18.0.0(stylelint@17.13.0(typescript@6.0.3))
|
stylelint-config-recommended: 18.0.0(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3))
|
||||||
stylelint-scss: 7.2.0(stylelint@17.13.0(typescript@6.0.3))
|
stylelint-scss: 7.2.0(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3))
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
postcss: 8.5.15
|
postcss: 8.5.15
|
||||||
|
|
||||||
stylelint-config-recommended@18.0.0(stylelint@17.13.0(typescript@6.0.3)):
|
stylelint-config-recommended@18.0.0(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
stylelint: 17.13.0(typescript@6.0.3)
|
stylelint: 17.13.0(supports-color@5.5.0)(typescript@6.0.3)
|
||||||
|
|
||||||
stylelint-config-standard-scss@17.0.0(postcss@8.5.15)(stylelint@17.13.0(typescript@6.0.3)):
|
stylelint-config-standard-scss@17.0.0(postcss@8.5.15)(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
stylelint: 17.13.0(typescript@6.0.3)
|
stylelint: 17.13.0(supports-color@5.5.0)(typescript@6.0.3)
|
||||||
stylelint-config-recommended-scss: 17.0.1(postcss@8.5.15)(stylelint@17.13.0(typescript@6.0.3))
|
stylelint-config-recommended-scss: 17.0.1(postcss@8.5.15)(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3))
|
||||||
stylelint-config-standard: 40.0.0(stylelint@17.13.0(typescript@6.0.3))
|
stylelint-config-standard: 40.0.0(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3))
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
postcss: 8.5.15
|
postcss: 8.5.15
|
||||||
|
|
||||||
stylelint-config-standard@40.0.0(stylelint@17.13.0(typescript@6.0.3)):
|
stylelint-config-standard@40.0.0(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
stylelint: 17.13.0(typescript@6.0.3)
|
stylelint: 17.13.0(supports-color@5.5.0)(typescript@6.0.3)
|
||||||
stylelint-config-recommended: 18.0.0(stylelint@17.13.0(typescript@6.0.3))
|
stylelint-config-recommended: 18.0.0(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3))
|
||||||
|
|
||||||
stylelint-scss@7.2.0(stylelint@17.13.0(typescript@6.0.3)):
|
stylelint-scss@7.2.0(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
|
'@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
|
||||||
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
|
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
|
||||||
@ -10265,13 +10462,13 @@ snapshots:
|
|||||||
postcss-resolve-nested-selector: 0.1.6
|
postcss-resolve-nested-selector: 0.1.6
|
||||||
postcss-selector-parser: 7.1.4
|
postcss-selector-parser: 7.1.4
|
||||||
postcss-value-parser: 4.2.0
|
postcss-value-parser: 4.2.0
|
||||||
stylelint: 17.13.0(typescript@6.0.3)
|
stylelint: 17.13.0(supports-color@5.5.0)(typescript@6.0.3)
|
||||||
|
|
||||||
stylelint-use-logical-spec@5.0.1(stylelint@17.13.0(typescript@6.0.3)):
|
stylelint-use-logical-spec@5.0.1(stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
stylelint: 17.13.0(typescript@6.0.3)
|
stylelint: 17.13.0(supports-color@5.5.0)(typescript@6.0.3)
|
||||||
|
|
||||||
stylelint@17.13.0(typescript@6.0.3):
|
stylelint@17.13.0(supports-color@5.5.0)(typescript@6.0.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
|
'@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
|
||||||
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
|
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
|
||||||
@ -10365,14 +10562,6 @@ snapshots:
|
|||||||
sax: 1.6.0
|
sax: 1.6.0
|
||||||
stable: 0.1.8
|
stable: 0.1.8
|
||||||
|
|
||||||
svgo@https://codeload.github.com/penpot/svgo/tar.gz/8c9b0e32e9cb5f106085260bd9375f3c91a5010b:
|
|
||||||
dependencies:
|
|
||||||
'@trysound/sax': 0.2.0
|
|
||||||
css-select: 5.2.2
|
|
||||||
css-tree: 3.2.1
|
|
||||||
csso: 5.0.5
|
|
||||||
lodash: 4.18.1
|
|
||||||
|
|
||||||
symbol-tree@3.2.4: {}
|
symbol-tree@3.2.4: {}
|
||||||
|
|
||||||
sync-child-process@1.0.2:
|
sync-child-process@1.0.2:
|
||||||
@ -10558,7 +10747,7 @@ snapshots:
|
|||||||
|
|
||||||
unpipe@1.0.0: {}
|
unpipe@1.0.0: {}
|
||||||
|
|
||||||
unplugin-dts@1.0.2(esbuild@0.28.1)(rolldown@1.0.3)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)):
|
unplugin-dts@1.0.2(esbuild@0.28.1)(rolldown@1.0.3)(supports-color@5.5.0)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rollup/pluginutils': 5.4.0
|
'@rollup/pluginutils': 5.4.0
|
||||||
'@volar/typescript': 2.4.28
|
'@volar/typescript': 2.4.28
|
||||||
@ -10634,9 +10823,9 @@ snapshots:
|
|||||||
remove-trailing-separator: 1.1.0
|
remove-trailing-separator: 1.1.0
|
||||||
replace-ext: 1.0.1
|
replace-ext: 1.0.1
|
||||||
|
|
||||||
vite-plugin-dts@5.0.2(esbuild@0.28.1)(rolldown@1.0.3)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)):
|
vite-plugin-dts@5.0.2(esbuild@0.28.1)(rolldown@1.0.3)(supports-color@5.5.0)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
unplugin-dts: 1.0.2(esbuild@0.28.1)(rolldown@1.0.3)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
unplugin-dts: 1.0.2(esbuild@0.28.1)(rolldown@1.0.3)(supports-color@5.5.0)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0))
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)
|
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.101.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -10699,9 +10888,9 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
xml-name-validator: 5.0.0
|
xml-name-validator: 5.0.0
|
||||||
|
|
||||||
wait-on@9.0.10:
|
wait-on@9.0.10(supports-color@5.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
axios: 1.17.0
|
axios: 1.17.0(supports-color@5.5.0)
|
||||||
joi: 18.2.1
|
joi: 18.2.1
|
||||||
lodash: 4.18.1
|
lodash: 4.18.1
|
||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.files.changes-builder :as pcb]
|
[app.common.files.changes-builder :as pcb]
|
||||||
|
[app.common.logging :as log]
|
||||||
[app.common.time :as ct]
|
[app.common.time :as ct]
|
||||||
[app.main.data.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.event :as ev]
|
[app.main.data.event :as ev]
|
||||||
@ -57,45 +58,57 @@
|
|||||||
|
|
||||||
(defn start-plugin!
|
(defn start-plugin!
|
||||||
[{:keys [plugin-id name version description host code permissions allow-background]} ^js extensions]
|
[{:keys [plugin-id name version description host code permissions allow-background]} ^js extensions]
|
||||||
(-> (.ɵloadPlugin
|
(let [load-plugin (unchecked-get ug/global "ɵloadPlugin")]
|
||||||
^js ug/global
|
(if (fn? load-plugin)
|
||||||
#js {:pluginId plugin-id
|
(-> (load-plugin
|
||||||
:name name
|
#js {:pluginId plugin-id
|
||||||
:version version
|
:name name
|
||||||
:description description
|
:version version
|
||||||
:host host
|
:description description
|
||||||
:code code
|
:host host
|
||||||
:allowBackground (boolean allow-background)
|
:code code
|
||||||
:permissions (apply array permissions)}
|
:allowBackground (boolean allow-background)
|
||||||
nil
|
:permissions (apply array permissions)}
|
||||||
extensions)
|
nil
|
||||||
|
extensions)
|
||||||
|
|
||||||
(p/catch (fn [cause]
|
(p/catch (fn [cause]
|
||||||
(ex/print-throwable cause :prefix "Plugin Error")
|
(ex/print-throwable cause :prefix "Plugin Error")
|
||||||
(errors/flash :cause cause :type :handled)))))
|
(errors/flash :cause cause :type :handled))))
|
||||||
|
|
||||||
|
(log/warn :hint "Plugin runtime not initialized yet"
|
||||||
|
:plugin-id plugin-id
|
||||||
|
:action "start-plugin!"))))
|
||||||
|
|
||||||
(defn- load-plugin!
|
(defn- load-plugin!
|
||||||
[{:keys [plugin-id name version description host code icon permissions]}]
|
[{:keys [plugin-id name version description host code icon permissions]}]
|
||||||
(st/emit! (pflag/clear plugin-id)
|
(st/emit! (pflag/clear plugin-id)
|
||||||
(save-current-plugin plugin-id))
|
(save-current-plugin plugin-id))
|
||||||
|
|
||||||
(-> (.ɵloadPlugin
|
(let [load-plugin (unchecked-get ug/global "ɵloadPlugin")]
|
||||||
^js ug/global
|
(if (fn? load-plugin)
|
||||||
#js {:pluginId plugin-id
|
(-> (load-plugin
|
||||||
:name name
|
#js {:pluginId plugin-id
|
||||||
:description description
|
:name name
|
||||||
:version version
|
:description description
|
||||||
:host host
|
:version version
|
||||||
:code code
|
:host host
|
||||||
:icon icon
|
:code code
|
||||||
:permissions (apply array permissions)}
|
:icon icon
|
||||||
(fn []
|
:permissions (apply array permissions)}
|
||||||
(st/emit! (remove-current-plugin plugin-id))))
|
(fn []
|
||||||
|
(st/emit! (remove-current-plugin plugin-id))))
|
||||||
|
|
||||||
(p/catch (fn [cause]
|
(p/catch (fn [cause]
|
||||||
(st/emit! (remove-current-plugin plugin-id))
|
(st/emit! (remove-current-plugin plugin-id))
|
||||||
(ex/print-throwable cause :prefix "Plugin Error")
|
(ex/print-throwable cause :prefix "Plugin Error")
|
||||||
(errors/flash :cause cause :type :handled)))))
|
(errors/flash :cause cause :type :handled))))
|
||||||
|
|
||||||
|
(do
|
||||||
|
(log/warn :hint "Plugin runtime not initialized yet"
|
||||||
|
:plugin-id plugin-id
|
||||||
|
:action "load-plugin!")
|
||||||
|
(st/emit! (remove-current-plugin plugin-id))))))
|
||||||
|
|
||||||
(defn open-plugin!
|
(defn open-plugin!
|
||||||
[{:keys [url] :as manifest} user-can-edit?]
|
[{:keys [url] :as manifest} user-can-edit?]
|
||||||
@ -135,10 +148,15 @@
|
|||||||
|
|
||||||
(defn close-plugin!
|
(defn close-plugin!
|
||||||
[{:keys [plugin-id]}]
|
[{:keys [plugin-id]}]
|
||||||
(try
|
(let [unload-plugin (unchecked-get ug/global "ɵunloadPlugin")]
|
||||||
(.ɵunloadPlugin ^js ug/global plugin-id)
|
(if (fn? unload-plugin)
|
||||||
(catch :default e
|
(try
|
||||||
(.error js/console "Error" e))))
|
(unload-plugin plugin-id)
|
||||||
|
(catch :default e
|
||||||
|
(.error js/console "Error" e)))
|
||||||
|
(log/warn :hint "Plugin runtime not initialized yet"
|
||||||
|
:plugin-id plugin-id
|
||||||
|
:action "close-plugin!"))))
|
||||||
|
|
||||||
(defn close-current-plugin
|
(defn close-current-plugin
|
||||||
[& {:keys [close-only-edition-plugins?]}]
|
[& {:keys [close-only-edition-plugins?]}]
|
||||||
|
|||||||
@ -504,8 +504,7 @@
|
|||||||
(rx/of (dwu/append-undo entry stack-undo?)))
|
(rx/of (dwu/append-undo entry stack-undo?)))
|
||||||
(rx/empty))))))
|
(rx/empty))))))
|
||||||
|
|
||||||
(rx/take-until stoper-s))
|
(rx/take-until stoper-s)))))
|
||||||
(rx/of (mcp/notify-other-tabs-disconnect)))))
|
|
||||||
|
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
(effect [_ _ _]
|
(effect [_ _ _]
|
||||||
|
|||||||
@ -10,13 +10,10 @@
|
|||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.main.broadcast :as mbc]
|
[app.main.broadcast :as mbc]
|
||||||
[app.main.data.event :as ev]
|
|
||||||
[app.main.data.notifications :as ntf]
|
|
||||||
[app.main.data.plugins :as dp]
|
[app.main.data.plugins :as dp]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.plugins.register :refer [mcp-plugin-id]]
|
[app.plugins.register :as preg]
|
||||||
[app.util.i18n :refer [tr]]
|
|
||||||
[app.util.timers :as ts]
|
[app.util.timers :as ts]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
@ -29,7 +26,7 @@
|
|||||||
{:code "plugin.js"
|
{:code "plugin.js"
|
||||||
:name "Penpot MCP Plugin"
|
:name "Penpot MCP Plugin"
|
||||||
:version 2
|
:version 2
|
||||||
:plugin-id mcp-plugin-id
|
:plugin-id preg/mcp-plugin-id
|
||||||
:description "This plugin enables interaction with the Penpot MCP server"
|
:description "This plugin enables interaction with the Penpot MCP server"
|
||||||
:allow-background true
|
:allow-background true
|
||||||
:permissions
|
:permissions
|
||||||
@ -39,6 +36,14 @@
|
|||||||
|
|
||||||
(defonce interval-sub (atom nil))
|
(defonce interval-sub (atom nil))
|
||||||
|
|
||||||
|
(defn connect-mcp
|
||||||
|
[]
|
||||||
|
(ptk/reify ::connect-mcp
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(rx/of (mbc/event :mcp/force-disconnect {})
|
||||||
|
(ptk/data-event ::connect)))))
|
||||||
|
|
||||||
(defn finalize-workspace?
|
(defn finalize-workspace?
|
||||||
[event]
|
[event]
|
||||||
(= (ptk/type event) :app.main.data.workspace/finalize-workspace))
|
(= (ptk/type event) :app.main.data.workspace/finalize-workspace))
|
||||||
@ -72,45 +77,6 @@
|
|||||||
(rx/dispose! @interval-sub)
|
(rx/dispose! @interval-sub)
|
||||||
(reset! interval-sub nil)))
|
(reset! interval-sub nil)))
|
||||||
|
|
||||||
(declare manage-mcp-notification)
|
|
||||||
|
|
||||||
(defn handle-pong
|
|
||||||
[{:keys [id data]}]
|
|
||||||
(ptk/reify ::handle-pong
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(let [mcp-state (get state :mcp)]
|
|
||||||
(cond
|
|
||||||
(= "connected" (:connection-status data))
|
|
||||||
(update state :mcp assoc :connected-tab id)
|
|
||||||
|
|
||||||
(and (= "disconnected" (:connection-status data))
|
|
||||||
(= id (:connected-tab mcp-state)))
|
|
||||||
(update state :mcp dissoc :connected-tab)
|
|
||||||
|
|
||||||
:else
|
|
||||||
state)))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ _ _]
|
|
||||||
(rx/of (manage-mcp-notification)))))
|
|
||||||
|
|
||||||
;; This event will arrive when a new workspace is open in another tab
|
|
||||||
(defn handle-ping
|
|
||||||
[]
|
|
||||||
(ptk/reify ::handle-ping
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(let [conn-status (get-in state [:mcp :connection-status])]
|
|
||||||
(rx/of (mbc/event :mcp/pong {:connection-status conn-status}))))))
|
|
||||||
|
|
||||||
(defn notify-other-tabs-disconnect
|
|
||||||
[]
|
|
||||||
(ptk/reify ::notify-other-tabs-disconnect
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ _ _]
|
|
||||||
(rx/of (mbc/event :mcp/pong {:connection-status "disconnected"})))))
|
|
||||||
|
|
||||||
;; This event will arrive when the mcp is enabled in the dashboard
|
;; This event will arrive when the mcp is enabled in the dashboard
|
||||||
(defn update-mcp-status
|
(defn update-mcp-status
|
||||||
[value]
|
[value]
|
||||||
@ -121,12 +87,10 @@
|
|||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/merge
|
(case value
|
||||||
(rx/of (manage-mcp-notification))
|
true (rx/of (connect-mcp))
|
||||||
(case value
|
false (rx/of (ptk/data-event ::disconnect))
|
||||||
true (rx/of (ptk/data-event ::connect))
|
nil))))
|
||||||
false (rx/of (ptk/data-event ::disconnect))
|
|
||||||
nil)))))
|
|
||||||
|
|
||||||
(defn update-mcp-connection-status
|
(defn update-mcp-connection-status
|
||||||
[value]
|
[value]
|
||||||
@ -137,20 +101,13 @@
|
|||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (manage-mcp-notification)
|
;; Only one MCP plugin instance may be active across browser tabs.
|
||||||
(mbc/event :mcp/pong {:connection-status value})))))
|
;; When this tab becomes connected, tell every other tab to
|
||||||
|
;; disconnect (which also stops their reconnect watcher). Otherwise
|
||||||
(defn connect-mcp
|
;; several tabs stay connected at once and the MCP server reports
|
||||||
[]
|
;; "multiple instances connected" and the agent fails.
|
||||||
(ptk/reify ::connect-mcp
|
(when (= "connected" value)
|
||||||
ptk/UpdateEvent
|
(rx/of (mbc/event :mcp/force-disconnect {}))))))
|
||||||
(update [_ state]
|
|
||||||
(update state :mcp assoc :connected-tab (:session-id state)))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ _ _]
|
|
||||||
(rx/of (mbc/event :mcp/force-disconect {})
|
|
||||||
(ptk/data-event ::connect)))))
|
|
||||||
|
|
||||||
;; This event will arrive when the user selects disconnect on the menu
|
;; This event will arrive when the user selects disconnect on the menu
|
||||||
;; or there is a broadcast message for disconnection
|
;; or there is a broadcast message for disconnection
|
||||||
@ -166,77 +123,54 @@
|
|||||||
(effect [_ _ _]
|
(effect [_ _ _]
|
||||||
(stop-reconnect-watcher!))))
|
(stop-reconnect-watcher!))))
|
||||||
|
|
||||||
(defn- manage-mcp-notification
|
|
||||||
[]
|
|
||||||
(ptk/reify ::manage-mcp-notification
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(let [mcp-state (get state :mcp)
|
|
||||||
|
|
||||||
mcp-enabled? (-> state :profile :props :mcp-enabled)
|
|
||||||
|
|
||||||
current-tab-id (get state :session-id)
|
|
||||||
connected-tab-id (get mcp-state :connected-tab)]
|
|
||||||
|
|
||||||
(if mcp-enabled?
|
|
||||||
(if (= connected-tab-id current-tab-id)
|
|
||||||
(rx/of (ntf/hide))
|
|
||||||
(rx/of (ntf/dialog
|
|
||||||
{:content (tr "notifications.mcp.active-in-another-tab")
|
|
||||||
:cancel {:label (tr "labels.dismiss")
|
|
||||||
:callback #(st/emit! (ntf/hide)
|
|
||||||
(ev/event {::ev/name "dismiss-mcp-tab-switch"
|
|
||||||
::ev/origin "workspace-notification"}))}
|
|
||||||
:accept {:label (tr "labels.switch")
|
|
||||||
:callback #(st/emit! (connect-mcp)
|
|
||||||
(ev/event {::ev/name "confirm-mcp-tab-switch"
|
|
||||||
::ev/origin "workspace-notification"}))}})))
|
|
||||||
(rx/of (ntf/hide)))))))
|
|
||||||
|
|
||||||
(defn init-mcp
|
(defn init-mcp
|
||||||
[stream]
|
[stream]
|
||||||
(->> (rp/cmd! :get-current-mcp-token)
|
;; Wait for plugins runtime to be initialized before starting the MCP plugin.
|
||||||
(rx/tap
|
;; This ensures global.ɵloadPlugin is available when start-plugin! is called.
|
||||||
(fn [{:keys [token]}]
|
(->> (rx/from (preg/wait-for-runtime))
|
||||||
(when token
|
(rx/mapcat
|
||||||
(dp/start-plugin!
|
(fn [_]
|
||||||
(assoc default-manifest
|
(->> (rp/cmd! :get-current-mcp-token)
|
||||||
:url (str (u/join cf/public-uri "plugins/mcp/manifest.json"))
|
(rx/tap
|
||||||
:host (str (u/join cf/public-uri "plugins/mcp/")))
|
(fn [{:keys [token]}]
|
||||||
|
(when token
|
||||||
|
(dp/start-plugin!
|
||||||
|
(assoc default-manifest
|
||||||
|
:url (str (u/join cf/public-uri "plugins/mcp/manifest.json"))
|
||||||
|
:host (str (u/join cf/public-uri "plugins/mcp/")))
|
||||||
|
|
||||||
;; API extension for MCP server
|
;; API extension for MCP server
|
||||||
#js {:mcp
|
#js {:mcp
|
||||||
#js
|
#js
|
||||||
{:getToken (constantly token)
|
{:getToken (constantly token)
|
||||||
:getServerUrl #(str cf/mcp-ws-uri)
|
:getServerUrl #(str cf/mcp-ws-uri)
|
||||||
:setMcpStatus
|
:setMcpStatus
|
||||||
(fn [status]
|
(fn [status]
|
||||||
(when (= status "connected")
|
(when (= status "connected")
|
||||||
(start-reconnect-watcher!))
|
(start-reconnect-watcher!))
|
||||||
(st/emit! (update-mcp-connection-status status))
|
(st/emit! (update-mcp-connection-status status))
|
||||||
(log/info :hint "MCP STATUS" :status status))
|
(log/info :hint "MCP STATUS" :status status))
|
||||||
|
|
||||||
:on
|
:on
|
||||||
(fn [event cb]
|
(fn [event cb]
|
||||||
(when-let [event
|
(when-let [event
|
||||||
(case event
|
(case event
|
||||||
"disconnect" ::disconnect
|
"disconnect" ::disconnect
|
||||||
"connect" ::connect
|
"connect" ::connect
|
||||||
nil)]
|
nil)]
|
||||||
|
|
||||||
(let [stopper (rx/filter finalize-workspace? stream)]
|
(let [stopper (rx/filter finalize-workspace? stream)]
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter (ptk/type? event))
|
(rx/filter (ptk/type? event))
|
||||||
(rx/take-until stopper)
|
(rx/take-until stopper)
|
||||||
(rx/subs! #(cb))))))}}))))
|
(rx/subs! #(cb))))))}})))))))))
|
||||||
(rx/ignore)))
|
|
||||||
|
|
||||||
(defn init
|
(defn init
|
||||||
[]
|
[]
|
||||||
(ptk/reify ::init
|
(ptk/reify ::init
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update state :mcp assoc :connected-tab (:session-id state) :active true))
|
(update state :mcp assoc :active true))
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
@ -251,22 +185,8 @@
|
|||||||
(rx/merge
|
(rx/merge
|
||||||
(init-mcp stream)
|
(init-mcp stream)
|
||||||
|
|
||||||
(rx/of (mbc/event :mcp/ping {}))
|
|
||||||
|
|
||||||
(->> mbc/stream
|
(->> mbc/stream
|
||||||
(rx/filter (mbc/type? :mcp/ping))
|
(rx/filter (mbc/type? :mcp/force-disconnect))
|
||||||
(rx/filter (fn [{:keys [id]}]
|
|
||||||
(not= session-id id)))
|
|
||||||
(rx/map handle-ping))
|
|
||||||
|
|
||||||
(->> mbc/stream
|
|
||||||
(rx/filter (mbc/type? :mcp/pong))
|
|
||||||
(rx/filter (fn [{:keys [id]}]
|
|
||||||
(not= session-id id)))
|
|
||||||
(rx/map handle-pong))
|
|
||||||
|
|
||||||
(->> mbc/stream
|
|
||||||
(rx/filter (mbc/type? :mcp/force-disconect))
|
|
||||||
(rx/filter (fn [{:keys [id]}]
|
(rx/filter (fn [{:keys [id]}]
|
||||||
(not= session-id id)))
|
(not= session-id id)))
|
||||||
(rx/map deref)
|
(rx/map deref)
|
||||||
@ -276,9 +196,9 @@
|
|||||||
(->> mbc/stream
|
(->> mbc/stream
|
||||||
(rx/filter (mbc/type? :mcp/enable))
|
(rx/filter (mbc/type? :mcp/enable))
|
||||||
(rx/mapcat (fn [_]
|
(rx/mapcat (fn [_]
|
||||||
;; NOTE: we don't need an explicit
|
;; Re-init so the force-disconnect
|
||||||
;; connect because the plugin has
|
;; listener is set up now that MCP
|
||||||
;; auto-connect
|
;; is enabled.
|
||||||
(rx/of (update-mcp-status true)
|
(rx/of (update-mcp-status true)
|
||||||
(init)))))
|
(init)))))
|
||||||
|
|
||||||
@ -286,7 +206,6 @@
|
|||||||
(rx/filter (mbc/type? :mcp/disable))
|
(rx/filter (mbc/type? :mcp/disable))
|
||||||
(rx/mapcat (fn [_]
|
(rx/mapcat (fn [_]
|
||||||
(rx/of (update-mcp-status false)
|
(rx/of (update-mcp-status false)
|
||||||
(init)
|
|
||||||
(user-disconnect-mcp))))))
|
(user-disconnect-mcp))))))
|
||||||
|
|
||||||
(rx/take-until stoper-s))))))
|
(rx/take-until stoper-s))))))
|
||||||
|
|||||||
@ -85,40 +85,70 @@
|
|||||||
(let [request (create-request file-id page-id shape-id tag)]
|
(let [request (create-request file-id page-id shape-id tag)]
|
||||||
(q/enqueue-unique queue request (partial render-thumbnail state file-id page-id shape-id tag))))
|
(q/enqueue-unique queue request (partial render-thumbnail state file-id page-id shape-id tag))))
|
||||||
|
|
||||||
|
(defn- clear-thumbnail-batch
|
||||||
|
[]
|
||||||
|
(let [pending (volatile! nil)]
|
||||||
|
(ptk/reify ::clear-thumbnail-batch
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(let [items (get state ::thumbnails-deletion-queue)]
|
||||||
|
(when (seq items)
|
||||||
|
(vreset! pending items))
|
||||||
|
(dissoc state ::thumbnails-deletion-queue)))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(let [items (reduce-kv (fn [acc object-id uri]
|
||||||
|
(when (str/starts-with? uri "blob:")
|
||||||
|
(tm/schedule-on-idle (partial wapi/revoke-uri uri)))
|
||||||
|
(conj acc object-id))
|
||||||
|
[]
|
||||||
|
@pending)]
|
||||||
|
(l/dbg :hint "clear-thumbnail-batch" :total (count items))
|
||||||
|
(->> (rx/from (partition-all 200 items))
|
||||||
|
(rx/mapcat
|
||||||
|
(fn [batch]
|
||||||
|
(l/dbg :hint "clear-thumbnail-batch" :batch-size (count batch))
|
||||||
|
(->> (rp/cmd! :delete-file-object-thumbnails
|
||||||
|
{:object-ids (vec batch)})
|
||||||
|
(rx/catch rx/empty)
|
||||||
|
(rx/ignore))))))))))
|
||||||
|
|
||||||
|
(defn remove-from-deletion-queue
|
||||||
|
"Removes an object-id from the pending deletion queue in state.
|
||||||
|
Used by update-thumbnail to cancel a pending batched delete before
|
||||||
|
creating a new thumbnail for the same object."
|
||||||
|
[object-id]
|
||||||
|
(ptk/reify ::remove-from-deletion-queue
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(update state ::thumbnails-deletion-queue dissoc object-id))))
|
||||||
|
|
||||||
(defn clear-thumbnail
|
(defn clear-thumbnail
|
||||||
([file-id page-id frame-id tag]
|
([file-id page-id frame-id tag]
|
||||||
(clear-thumbnail file-id (thc/fmt-object-id file-id page-id frame-id tag)))
|
(clear-thumbnail file-id (thc/fmt-object-id file-id page-id frame-id tag)))
|
||||||
([file-id object-id]
|
([_file-id object-id]
|
||||||
(let [pending (volatile! false)]
|
(ptk/reify ::clear-thumbnail
|
||||||
(ptk/reify ::clear-thumbnail
|
cljs.core/IDeref
|
||||||
cljs.core/IDeref
|
(-deref [_] object-id)
|
||||||
(-deref [_] object-id)
|
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
|
(let [uri (dm/get-in state [:thumbnails object-id])]
|
||||||
|
(l/dbg :hint "clear-thumbnail" :object-id object-id :uri uri)
|
||||||
(-> state
|
(-> state
|
||||||
(update :thumbnails
|
(update ::thumbnails-deletion-queue assoc object-id uri)
|
||||||
(fn [thumbs]
|
(update :thumbnails dissoc object-id)
|
||||||
(if-let [uri (get thumbs object-id)]
|
(update :thumbnails-meta dissoc object-id))))
|
||||||
(do (vreset! pending uri)
|
|
||||||
(dissoc thumbs object-id))
|
|
||||||
thumbs)))
|
|
||||||
(update :thumbnails-meta dissoc object-id)))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ stream]
|
||||||
(if-let [uri @pending]
|
(let [stopper-s (->> stream
|
||||||
(do
|
(rx/filter (ptk/type? ::clear-thumbnail)))]
|
||||||
(l/trc :hint "clear-thumbnail" :uri uri)
|
(->> (rx/timer 200)
|
||||||
(when (str/starts-with? uri "blob:")
|
(rx/take 1)
|
||||||
(tm/schedule-on-idle (partial wapi/revoke-uri uri)))
|
(rx/map (fn [_] (clear-thumbnail-batch)))
|
||||||
|
(rx/take-until stopper-s)))))))
|
||||||
(let [params {:file-id file-id
|
|
||||||
:object-id object-id}]
|
|
||||||
(->> (rp/cmd! :delete-file-object-thumbnail params)
|
|
||||||
(rx/catch rx/empty)
|
|
||||||
(rx/ignore))))
|
|
||||||
(rx/empty)))))))
|
|
||||||
|
|
||||||
(defn assoc-thumbnail
|
(defn assoc-thumbnail
|
||||||
[object-id uri]
|
[object-id uri]
|
||||||
@ -173,7 +203,8 @@
|
|||||||
:tag (or tag "frame")}]
|
:tag (or tag "frame")}]
|
||||||
|
|
||||||
(rx/merge
|
(rx/merge
|
||||||
(rx/of (assoc-thumbnail object-id uri))
|
(rx/of (assoc-thumbnail object-id uri)
|
||||||
|
(remove-from-deletion-queue object-id))
|
||||||
(->> (rp/cmd! :create-file-object-thumbnail params)
|
(->> (rp/cmd! :create-file-object-thumbnail params)
|
||||||
(rx/catch rx/empty)
|
(rx/catch rx/empty)
|
||||||
(rx/ignore))))))
|
(rx/ignore))))))
|
||||||
@ -305,6 +336,14 @@
|
|||||||
;; and interrupt any ongoing update-thumbnail process
|
;; and interrupt any ongoing update-thumbnail process
|
||||||
;; related to current frame-id
|
;; related to current frame-id
|
||||||
(->> all-commits-s
|
(->> all-commits-s
|
||||||
|
;; Ensure each clear-thumbnail event is dispatched in its
|
||||||
|
;; own macrotask tick. Without this, multiple changes
|
||||||
|
;; arriving on the same synchronous tick would emit
|
||||||
|
;; several clear-thumbnail events back-to-back, causing
|
||||||
|
;; their debounce timers (rx/take-until stopper-s) to
|
||||||
|
;; race and potentially leave multiple clear-thumbnail-batch
|
||||||
|
;; timers alive simultaneously.
|
||||||
|
(rx/observe-on :async)
|
||||||
(rx/mapcat (fn [[tag frame-id]]
|
(rx/mapcat (fn [[tag frame-id]]
|
||||||
(rx/of (clear-thumbnail file-id page-id frame-id tag)))))
|
(rx/of (clear-thumbnail file-id page-id frame-id tag)))))
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.files.helpers :as cph]
|
[app.common.files.helpers :as cph]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.shape-tree :as ctt]
|
[app.common.types.shape-tree :as ctt]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.types.tokens-lib :as ctob]
|
[app.common.types.tokens-lib :as ctob]
|
||||||
@ -155,6 +156,14 @@
|
|||||||
(def mcp
|
(def mcp
|
||||||
(l/derived :mcp st/state))
|
(l/derived :mcp st/state))
|
||||||
|
|
||||||
|
(def mcp-key-expired?
|
||||||
|
(l/derived (fn [state]
|
||||||
|
(when-let [expires-at (some->> (:access-tokens state)
|
||||||
|
(some #(when (= (:type %) "mcp") %))
|
||||||
|
:expires-at)]
|
||||||
|
(> (ct/now) expires-at)))
|
||||||
|
st/state))
|
||||||
|
|
||||||
(def workspace-drawing
|
(def workspace-drawing
|
||||||
(l/derived :workspace-drawing st/state))
|
(l/derived :workspace-drawing st/state))
|
||||||
|
|
||||||
|
|||||||
@ -37,8 +37,20 @@
|
|||||||
;; If the error is a stale-asset error (cross-build
|
;; If the error is a stale-asset error (cross-build
|
||||||
;; module mismatch), force a hard page reload instead
|
;; module mismatch), force a hard page reload instead
|
||||||
;; of showing the error page to the user.
|
;; of showing the error page to the user.
|
||||||
(if (errors/stale-asset-error? error)
|
(cond
|
||||||
|
(errors/stale-asset-error? error)
|
||||||
(cf/throttled-reload :reason (ex-message error))
|
(cf/throttled-reload :reason (ex-message error))
|
||||||
|
|
||||||
|
;; If the error is known to be harmless (browser
|
||||||
|
;; extensions, React DOM conflicts, etc.), ignore it
|
||||||
|
;; silently — the global uncaught-error-handler
|
||||||
|
;; already does this, but react-error-boundary's
|
||||||
|
;; onError fires independently of the window.onerror
|
||||||
|
;; pipeline, so we must also filter here.
|
||||||
|
(errors/is-ignorable-exception? error)
|
||||||
|
nil
|
||||||
|
|
||||||
|
:else
|
||||||
(do
|
(do
|
||||||
(set! errors/last-exception error)
|
(set! errors/last-exception error)
|
||||||
(ex/print-throwable error)
|
(ex/print-throwable error)
|
||||||
|
|||||||
@ -54,16 +54,15 @@
|
|||||||
;; The content can arrive in markdown format, in these cases
|
;; The content can arrive in markdown format, in these cases
|
||||||
;; we will use the prop is-html to true to indicate it and
|
;; we will use the prop is-html to true to indicate it and
|
||||||
;; that the html injection is performed and the necessary css classes are applied.
|
;; that the html injection is performed and the necessary css classes are applied.
|
||||||
[:div {:class (stl/css :context-text)
|
(if is-html
|
||||||
:dangerouslySetInnerHTML (when is-html #js {:__html content})}
|
[:div {:class (stl/css :context-text)
|
||||||
(when-not is-html
|
:dangerouslySetInnerHTML #js {:__html content}}]
|
||||||
[:*
|
[:div {:class (stl/css :context-text)}
|
||||||
content
|
content
|
||||||
(when (some? links)
|
(when (some? links)
|
||||||
(for [[index link] (d/enumerate links)]
|
(for [[index link] (d/enumerate links)]
|
||||||
;; TODO Review this component
|
;; TODO Review this component
|
||||||
[:> lb/link-button* {:class (stl/css :link)
|
[:> lb/link-button* {:class (stl/css :link)
|
||||||
:on-click (:callback link)
|
:on-click (:callback link)
|
||||||
:value (:label link)
|
:value (:label link)
|
||||||
:key (dm/str "link-" index)}]))])]])
|
:key (dm/str "link-" index)}]))])])
|
||||||
|
|
||||||
|
|||||||
@ -406,18 +406,16 @@
|
|||||||
(mf/defc mcp-server-section*
|
(mf/defc mcp-server-section*
|
||||||
{::mf/private true}
|
{::mf/private true}
|
||||||
[]
|
[]
|
||||||
(let [tokens (mf/deref refs/access-tokens)
|
(let [tokens (mf/deref refs/access-tokens)
|
||||||
profile (mf/deref refs/profile)
|
profile (mf/deref refs/profile)
|
||||||
|
mcp-key-expired? (mf/deref refs/mcp-key-expired?)
|
||||||
|
|
||||||
mcp-key (some #(when (= (:type %) "mcp") %) tokens)
|
mcp-key (some #(when (= (:type %) "mcp") %) tokens)
|
||||||
mcp-token (:token mcp-key "")
|
mcp-token (:token mcp-key "")
|
||||||
mcp-url (dm/str cf/mcp-server-url "?userToken=" mcp-token)
|
mcp-url (dm/str cf/mcp-server-url "?userToken=" mcp-token)
|
||||||
mcp-enabled? (true? (-> profile :props :mcp-enabled))
|
mcp-enabled? (true? (-> profile :props :mcp-enabled))
|
||||||
|
|
||||||
expires-at (:expires-at mcp-key)
|
show-enabled? (and mcp-enabled? (false? mcp-key-expired?))
|
||||||
expired? (and (some? expires-at) (> (ct/now) expires-at))
|
|
||||||
|
|
||||||
show-enabled? (and mcp-enabled? (false? expired?))
|
|
||||||
|
|
||||||
tooltip-id
|
tooltip-id
|
||||||
(mf/use-id)
|
(mf/use-id)
|
||||||
@ -494,7 +492,7 @@
|
|||||||
(tr "integrations.mcp-server.status")]
|
(tr "integrations.mcp-server.status")]
|
||||||
|
|
||||||
[:div {:class (stl/css :mcp-server-block)}
|
[:div {:class (stl/css :mcp-server-block)}
|
||||||
(when expired?
|
(when mcp-key-expired?
|
||||||
[:> notification-pill* {:level :error
|
[:> notification-pill* {:level :error
|
||||||
:type :context}
|
:type :context}
|
||||||
[:div {:class (stl/css :mcp-server-notification)}
|
[:div {:class (stl/css :mcp-server-notification)}
|
||||||
@ -517,7 +515,7 @@
|
|||||||
(when (and (false? mcp-enabled?) (nil? mcp-key))
|
(when (and (false? mcp-enabled?) (nil? mcp-key))
|
||||||
[:div {:class (stl/css :mcp-server-switch-cover)
|
[:div {:class (stl/css :mcp-server-switch-cover)
|
||||||
:on-click handle-generate-mcp-key}])
|
:on-click handle-generate-mcp-key}])
|
||||||
(when (true? expired?)
|
(when (true? mcp-key-expired?)
|
||||||
[:div {:class (stl/css :mcp-server-switch-cover)
|
[:div {:class (stl/css :mcp-server-switch-cover)
|
||||||
:on-click handle-regenerate-mcp-key}])]]]
|
:on-click handle-regenerate-mcp-key}])]]]
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.files.helpers :as cfh]
|
[app.common.files.helpers :as cfh]
|
||||||
[app.common.time :as ct]
|
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.main.data.common :as dcm]
|
[app.main.data.common :as dcm]
|
||||||
@ -791,20 +790,15 @@
|
|||||||
[{:keys [on-close]}]
|
[{:keys [on-close]}]
|
||||||
(let [plugins? (features/active-feature? @st/state "plugins/runtime")
|
(let [plugins? (features/active-feature? @st/state "plugins/runtime")
|
||||||
|
|
||||||
profile (mf/deref refs/profile)
|
profile (mf/deref refs/profile)
|
||||||
mcp (mf/deref refs/mcp)
|
mcp (mf/deref refs/mcp)
|
||||||
tokens (mf/deref refs/access-tokens)
|
mcp-key-expired? (mf/deref refs/mcp-key-expired?)
|
||||||
|
|
||||||
expires-at (some->> tokens
|
|
||||||
(some #(when (= (:type %) "mcp") %))
|
|
||||||
:expires-at)
|
|
||||||
expired? (and (some? expires-at) (> (ct/now) expires-at))
|
|
||||||
|
|
||||||
mcp-enabled? (true? (-> profile :props :mcp-enabled))
|
mcp-enabled? (true? (-> profile :props :mcp-enabled))
|
||||||
mcp-connection (get mcp :connection-status)
|
mcp-connection (get mcp :connection-status)
|
||||||
mcp-connected? (= mcp-connection "connected")
|
mcp-connected? (= mcp-connection "connected")
|
||||||
|
|
||||||
show-enabled? (and mcp-enabled? (false? expired?))
|
show-enabled? (and mcp-enabled? (false? mcp-key-expired?))
|
||||||
|
|
||||||
on-nav-to-integrations
|
on-nav-to-integrations
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@ -843,7 +837,7 @@
|
|||||||
:pos-6 plugins?)
|
:pos-6 plugins?)
|
||||||
:on-close on-close}
|
:on-close on-close}
|
||||||
|
|
||||||
(when (and show-enabled? (not expired?))
|
(when (and show-enabled? (not mcp-key-expired?))
|
||||||
[:> dropdown-menu-item* {:id "mcp-menu-toggle-mcp-plugin"
|
[:> dropdown-menu-item* {:id "mcp-menu-toggle-mcp-plugin"
|
||||||
:class (stl/css :base-menu-item :submenu-item)
|
:class (stl/css :base-menu-item :submenu-item)
|
||||||
:on-click on-toggle-mcp-plugin
|
:on-click on-toggle-mcp-plugin
|
||||||
@ -865,7 +859,6 @@
|
|||||||
(mf/defc menu*
|
(mf/defc menu*
|
||||||
[{:keys [layout file]}]
|
[{:keys [layout file]}]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [profile (mf/deref refs/profile)
|
||||||
mcp (mf/deref refs/mcp)
|
|
||||||
|
|
||||||
show-menu* (mf/use-state false)
|
show-menu* (mf/use-state false)
|
||||||
show-menu? (deref show-menu*)
|
show-menu? (deref show-menu*)
|
||||||
@ -1062,11 +1055,8 @@
|
|||||||
:class (stl/css :item-arrow)}]])
|
:class (stl/css :item-arrow)}]])
|
||||||
|
|
||||||
(when (contains? cf/flags :mcp)
|
(when (contains? cf/flags :mcp)
|
||||||
(let [tokens (mf/deref refs/access-tokens)
|
(let [mcp (mf/deref refs/mcp)
|
||||||
expires-at (some->> tokens
|
mcp-key-expired? (mf/deref refs/mcp-key-expired?)
|
||||||
(some #(when (= (:type %) "mcp") %))
|
|
||||||
:expires-at)
|
|
||||||
expired? (and (some? expires-at) (> (ct/now) expires-at))
|
|
||||||
|
|
||||||
mcp-enabled? (true? (-> profile :props :mcp-enabled))
|
mcp-enabled? (true? (-> profile :props :mcp-enabled))
|
||||||
mcp-connection (get mcp :connection-status)
|
mcp-connection (get mcp :connection-status)
|
||||||
@ -1075,7 +1065,7 @@
|
|||||||
|
|
||||||
active? (and mcp-enabled? mcp-connected?)
|
active? (and mcp-enabled? mcp-connected?)
|
||||||
failed? (or (and mcp-enabled? mcp-error?)
|
failed? (or (and mcp-enabled? mcp-error?)
|
||||||
(true? expired?))]
|
(true? mcp-key-expired?))]
|
||||||
|
|
||||||
[:> dropdown-menu-item* {:class (stl/css :base-menu-item :menu-item)
|
[:> dropdown-menu-item* {:class (stl/css :base-menu-item :menu-item)
|
||||||
:on-click on-menu-click
|
:on-click on-menu-click
|
||||||
|
|||||||
@ -8,15 +8,18 @@
|
|||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
|
[app.config :as cf]
|
||||||
[app.main.data.event :as ev]
|
[app.main.data.event :as ev]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.common :as dwc]
|
[app.main.data.workspace.common :as dwc]
|
||||||
|
[app.main.data.workspace.mcp :as mcp]
|
||||||
[app.main.data.workspace.media :as dwm]
|
[app.main.data.workspace.media :as dwm]
|
||||||
[app.main.data.workspace.shortcuts :as sc]
|
[app.main.data.workspace.shortcuts :as sc]
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.components.dropdown-menu :refer [dropdown-menu* dropdown-menu-item*]]
|
||||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||||
[app.main.ui.context :as ctx]
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as deprecated-icon]
|
[app.main.ui.icons :as deprecated-icon]
|
||||||
@ -26,6 +29,61 @@
|
|||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(mf/defc mcp-indicator*
|
||||||
|
[]
|
||||||
|
(let [profile (mf/deref refs/profile)
|
||||||
|
mcp (mf/deref refs/mcp)
|
||||||
|
mcp-key-expired? (mf/deref refs/mcp-key-expired?)
|
||||||
|
|
||||||
|
mcp-enabled? (true? (-> profile :props :mcp-enabled))
|
||||||
|
mcp-connected? (= "connected" (:connection-status mcp))
|
||||||
|
show-indicator? (and mcp-enabled? (false? mcp-key-expired?))
|
||||||
|
|
||||||
|
mcp-menu-open* (mf/use-state false)
|
||||||
|
mcp-menu-open? (deref mcp-menu-open*)
|
||||||
|
|
||||||
|
toggle-mcp-menu
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [event]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(swap! mcp-menu-open* not)))
|
||||||
|
|
||||||
|
close-mcp-menu
|
||||||
|
(mf/use-fn
|
||||||
|
#(reset! mcp-menu-open* false))
|
||||||
|
|
||||||
|
connect-mcp
|
||||||
|
(mf/use-fn
|
||||||
|
#(st/emit! (mcp/connect-mcp)
|
||||||
|
(ev/event {::ev/name "connect-mcp-plugin"
|
||||||
|
::ev/origin "workspace:toolbar"})))]
|
||||||
|
(when show-indicator?
|
||||||
|
[:li
|
||||||
|
[:button
|
||||||
|
{:title (tr "workspace.toolbar.mcp")
|
||||||
|
:aria-label (tr "workspace.toolbar.mcp")
|
||||||
|
:class (stl/css-case :main-toolbar-options-button true
|
||||||
|
:mcp-button true
|
||||||
|
:selected mcp-menu-open?)
|
||||||
|
:on-click toggle-mcp-menu
|
||||||
|
:data-tool "mcp"
|
||||||
|
:data-testid "mcp-btn"}
|
||||||
|
[:span {:class (stl/css-case :mcp-status-dot true
|
||||||
|
:connected mcp-connected?)}]
|
||||||
|
[:span {:class (stl/css-case :mcp-button-label true
|
||||||
|
:connected mcp-connected?)}
|
||||||
|
(tr "workspace.toolbar.mcp")]]
|
||||||
|
[:> dropdown-menu* {:show mcp-menu-open?
|
||||||
|
:on-close close-mcp-menu
|
||||||
|
:class (stl/css :mcp-menu)}
|
||||||
|
(if mcp-connected?
|
||||||
|
[:li {:class (stl/css :mcp-menu-info)
|
||||||
|
:role "presentation"}
|
||||||
|
(tr "workspace.toolbar.mcp-connected")]
|
||||||
|
[:> dropdown-menu-item* {:class (stl/css :mcp-menu-item)
|
||||||
|
:on-click connect-mcp}
|
||||||
|
(tr "workspace.toolbar.mcp-connect-here")])]])))
|
||||||
|
|
||||||
(mf/defc image-upload*
|
(mf/defc image-upload*
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[]
|
[]
|
||||||
@ -221,12 +279,13 @@
|
|||||||
{:title "Debugging tool"
|
{:title "Debugging tool"
|
||||||
:class (stl/css-case :main-toolbar-options-button true :selected (contains? layout :debug-panel))
|
:class (stl/css-case :main-toolbar-options-button true :selected (contains? layout :debug-panel))
|
||||||
:on-click toggle-debug-panel}
|
:on-click toggle-debug-panel}
|
||||||
deprecated-icon/bug]])]]
|
deprecated-icon/bug]])
|
||||||
|
|
||||||
|
(when (contains? cf/flags :mcp)
|
||||||
|
[:> mcp-indicator*])]]
|
||||||
|
|
||||||
[:button {:title (tr "workspace.toolbar.toggle-toolbar")
|
[:button {:title (tr "workspace.toolbar.toggle-toolbar")
|
||||||
:aria-label (tr "workspace.toolbar.toggle-toolbar")
|
:aria-label (tr "workspace.toolbar.toggle-toolbar")
|
||||||
:class (stl/css :toolbar-handler)
|
:class (stl/css :toolbar-handler)
|
||||||
:on-click toggle-toolbar}
|
:on-click toggle-toolbar}
|
||||||
[:div {:class (stl/css :toolbar-handler-btn)}]]])))
|
[:div {:class (stl/css :toolbar-handler-btn)}]]])))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,9 @@
|
|||||||
// Copyright (c) KALEIDOS INC Sucursal en España SL
|
// Copyright (c) KALEIDOS INC Sucursal en España SL
|
||||||
|
|
||||||
@use "refactor/common-refactor.scss" as deprecated;
|
@use "refactor/common-refactor.scss" as deprecated;
|
||||||
|
@use "ds/_borders.scss" as *;
|
||||||
|
@use "ds/_utils.scss" as *;
|
||||||
|
@use "ds/typography.scss" as t;
|
||||||
|
|
||||||
.main-toolbar {
|
.main-toolbar {
|
||||||
cursor: initial;
|
cursor: initial;
|
||||||
@ -83,6 +86,102 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mcp-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--sp-xs);
|
||||||
|
width: fit-content;
|
||||||
|
margin-inline-start: var(--sp-xs);
|
||||||
|
padding-inline: var(--sp-s);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-button-label {
|
||||||
|
@include t.use-typography("body-small");
|
||||||
|
|
||||||
|
&.connected {
|
||||||
|
color: var(--color-accent-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-status-dot {
|
||||||
|
// Connection indicator placed before the label, vertically centered:
|
||||||
|
// a muted gray when disconnected, the primary accent when connected.
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
inline-size: px2rem(6);
|
||||||
|
block-size: px2rem(6);
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--color-background-disabled);
|
||||||
|
|
||||||
|
&.connected {
|
||||||
|
background-color: var(--color-accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
// One-shot "blob" ripple that confirms the moment the tab becomes
|
||||||
|
// connected (e.g. after using "Switch here"). Triggered purely by the
|
||||||
|
// `.connected` class appearing, in sync with the color change.
|
||||||
|
&.connected::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--color-accent-primary);
|
||||||
|
opacity: 0;
|
||||||
|
animation: mcp-status-blob 0.5s ease-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mcp-status-blob {
|
||||||
|
from {
|
||||||
|
opacity: 0.5;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(2.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-menu {
|
||||||
|
@include deprecated.menu-shadow;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
inset-block-start: calc(100% + var(--sp-xs));
|
||||||
|
inset-inline-start: var(--sp-xs);
|
||||||
|
z-index: var(--z-index-dropdown);
|
||||||
|
margin: 0;
|
||||||
|
padding: var(--sp-xs);
|
||||||
|
list-style: none;
|
||||||
|
border: $b-1 solid var(--panel-border-color);
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--menu-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-interactive informational text inside the menu (no hover, not focusable).
|
||||||
|
.mcp-menu-info {
|
||||||
|
@include t.use-typography("body-small");
|
||||||
|
|
||||||
|
padding: var(--sp-s) var(--sp-m);
|
||||||
|
color: var(--color-foreground-secondary);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-menu-item {
|
||||||
|
@include t.use-typography("body-small");
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--sp-s) var(--sp-m);
|
||||||
|
border-radius: $br-8;
|
||||||
|
color: var(--menu-foreground-color);
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--menu-background-color-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.toolbar-handler {
|
.toolbar-handler {
|
||||||
@include deprecated.flex-center;
|
@include deprecated.flex-center;
|
||||||
@include deprecated.button-style;
|
@include deprecated.button-style;
|
||||||
|
|||||||
@ -17,14 +17,17 @@
|
|||||||
[app.plugins.grid :as grid]
|
[app.plugins.grid :as grid]
|
||||||
[app.plugins.library :as library]
|
[app.plugins.library :as library]
|
||||||
[app.plugins.public-utils]
|
[app.plugins.public-utils]
|
||||||
|
[app.plugins.register :as preg]
|
||||||
[app.plugins.ruler-guides :as rg]
|
[app.plugins.ruler-guides :as rg]
|
||||||
[app.plugins.shape :as shape]
|
[app.plugins.shape :as shape]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
(defn init-plugins-runtime!
|
(defn init-plugins-runtime
|
||||||
[]
|
[]
|
||||||
(runtime/initPluginsRuntime (fn [plugin-id] (api/create-context plugin-id))))
|
(runtime/initPluginsRuntime (fn [plugin-id] (api/create-context plugin-id)))
|
||||||
|
;; Signal that runtime is ready
|
||||||
|
(preg/signal-runtime-ready))
|
||||||
|
|
||||||
(defn initialize
|
(defn initialize
|
||||||
[]
|
[]
|
||||||
@ -38,7 +41,7 @@
|
|||||||
(rx/observe-on :async)
|
(rx/observe-on :async)
|
||||||
(rx/filter #(features/active-feature? @st/state "plugins/runtime"))
|
(rx/filter #(features/active-feature? @st/state "plugins/runtime"))
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/tap init-plugins-runtime!)
|
(rx/tap init-plugins-runtime)
|
||||||
(rx/ignore)))))
|
(rx/ignore)))))
|
||||||
|
|
||||||
;; Prevent circular dependency
|
;; Prevent circular dependency
|
||||||
|
|||||||
@ -15,12 +15,28 @@
|
|||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[beicon.v2.core :as rx]))
|
[beicon.v2.core :as rx]
|
||||||
|
[promesa.core :as p]))
|
||||||
|
|
||||||
;; Needs to be here because moving it to `app.main.data.workspace.mcp` will
|
;; Needs to be here because moving it to `app.main.data.workspace.mcp` will
|
||||||
;; cause a circular dependency
|
;; cause a circular dependency
|
||||||
(def mcp-plugin-id "96dfa740-005d-8020-8007-55ede24a2bae")
|
(def mcp-plugin-id "96dfa740-005d-8020-8007-55ede24a2bae")
|
||||||
|
|
||||||
|
;; Promise that resolves when plugins runtime is initialized.
|
||||||
|
;; Lives here to avoid circular dependency: workspace.mcp -> app.plugins -> app.plugins.api -> workspace
|
||||||
|
(defonce ^:private runtime-ready-promise (p/deferred))
|
||||||
|
|
||||||
|
(defn wait-for-runtime
|
||||||
|
"Returns a promise that resolves when plugins runtime is initialized."
|
||||||
|
[]
|
||||||
|
runtime-ready-promise)
|
||||||
|
|
||||||
|
(defn signal-runtime-ready
|
||||||
|
"Signals that plugins runtime has been initialized. Called by app.plugins/init-plugins-runtime."
|
||||||
|
[]
|
||||||
|
(when (p/pending? runtime-ready-promise)
|
||||||
|
(p/resolve! runtime-ready-promise true)))
|
||||||
|
|
||||||
;; Stores the installed plugins information
|
;; Stores the installed plugins information
|
||||||
(defonce ^:private registry (atom {}))
|
(defonce ^:private registry (atom {}))
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,14 @@
|
|||||||
:hint "operation aborted")))
|
:hint "operation aborted")))
|
||||||
(obj/set! image "src" uri)
|
(obj/set! image "src" uri)
|
||||||
(fn []
|
(fn []
|
||||||
(obj/set! image "src" "")
|
;; NOTE: We intentionally do NOT set `image.src = ""` here.
|
||||||
|
;; Doing so discards the decoded pixel data immediately when this
|
||||||
|
;; observable completes, but downstream operators (e.g. drawImage /
|
||||||
|
;; createImageBitmap in `render-image-bitmap`) still need to read
|
||||||
|
;; the pixel data after the image is emitted. Clearing `src` before
|
||||||
|
;; the downstream pipeline finishes causes a NotReadableError
|
||||||
|
;; ("The requested file could not be read..."). The image element
|
||||||
|
;; will be garbage collected naturally when no references remain.
|
||||||
(obj/set! image "onload" nil)
|
(obj/set! image "onload" nil)
|
||||||
(obj/set! image "onerror" nil)
|
(obj/set! image "onerror" nil)
|
||||||
(obj/set! image "onabort" nil))))))
|
(obj/set! image "onabort" nil))))))
|
||||||
@ -57,10 +64,13 @@
|
|||||||
(defn- svg-get-adjusted-size
|
(defn- svg-get-adjusted-size
|
||||||
"Returns the adjusted size of an SVG."
|
"Returns the adjusted size of an SVG."
|
||||||
[width height max]
|
[width height max]
|
||||||
(let [ratio (/ width height)]
|
;; Guard against zero/NaN dimensions that would cause division by zero
|
||||||
(if (< width height)
|
;; or produce invalid sizes, leading to createImageBitmap failures.
|
||||||
[max (* max (/ 1 ratio))]
|
(when (and (pos? width) (pos? height))
|
||||||
[(* max ratio) max])))
|
(let [ratio (/ width height)]
|
||||||
|
(if (< width height)
|
||||||
|
[max (* max (/ 1 ratio))]
|
||||||
|
[(* max ratio) max]))))
|
||||||
|
|
||||||
(defn- svg-get-size-from-viewbox
|
(defn- svg-get-size-from-viewbox
|
||||||
"Returns the size of an SVG from its viewbox."
|
"Returns the size of an SVG from its viewbox."
|
||||||
@ -101,7 +111,10 @@
|
|||||||
"Sets the intrinsic size of an SVG to the given max size."
|
"Sets the intrinsic size of an SVG to the given max size."
|
||||||
[^js svg max]
|
[^js svg max]
|
||||||
(let [doc (get-document-element svg)
|
(let [doc (get-document-element svg)
|
||||||
[w h] (svg-get-size svg max)]
|
[w h] (or (svg-get-size svg max)
|
||||||
|
;; Fallback: if we can't determine size from viewBox or
|
||||||
|
;; intrinsic attributes, use the max size as a square.
|
||||||
|
[max max])]
|
||||||
(dom/set-attribute! doc "width" (dm/str w))
|
(dom/set-attribute! doc "width" (dm/str w))
|
||||||
(dom/set-attribute! doc "height" (dm/str h)))
|
(dom/set-attribute! doc "height" (dm/str h)))
|
||||||
svg)
|
svg)
|
||||||
|
|||||||
@ -24,5 +24,5 @@
|
|||||||
|
|
||||||
(defn ^:export plugins []
|
(defn ^:export plugins []
|
||||||
(st/emit! (features/enable-feature "plugins/runtime"))
|
(st/emit! (features/enable-feature "plugins/runtime"))
|
||||||
(plugins/init-plugins-runtime!)
|
(plugins/init-plugins-runtime)
|
||||||
nil)
|
nil)
|
||||||
|
|||||||
50
frontend/test/frontend_tests/data/workspace_mcp_test.cljs
Normal file
50
frontend/test/frontend_tests/data/workspace_mcp_test.cljs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
;; 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 Sucursal en España SL
|
||||||
|
|
||||||
|
(ns frontend-tests.data.workspace-mcp-test
|
||||||
|
(:require
|
||||||
|
[app.main.data.workspace.mcp :as mcp]
|
||||||
|
[cljs.test :as t :include-macros true]
|
||||||
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
(t/deftest test-set-mcp-active
|
||||||
|
(t/testing "sets :active to true"
|
||||||
|
(let [state {:mcp {:active false}}
|
||||||
|
result (ptk/update (mcp/set-mcp-active true) state)]
|
||||||
|
(t/is (true? (get-in result [:mcp :active])))))
|
||||||
|
|
||||||
|
(t/testing "sets :active to false"
|
||||||
|
(let [state {:mcp {:active true}}
|
||||||
|
result (ptk/update (mcp/set-mcp-active false) state)]
|
||||||
|
(t/is (false? (get-in result [:mcp :active]))))))
|
||||||
|
|
||||||
|
(t/deftest test-update-mcp-status
|
||||||
|
(t/testing "enables MCP in profile props"
|
||||||
|
(let [state {:profile {:props {:mcp-enabled false}}}
|
||||||
|
result (ptk/update (mcp/update-mcp-status true) state)]
|
||||||
|
(t/is (true? (get-in result [:profile :props :mcp-enabled])))))
|
||||||
|
|
||||||
|
(t/testing "disables MCP in profile props"
|
||||||
|
(let [state {:profile {:props {:mcp-enabled true}}}
|
||||||
|
result (ptk/update (mcp/update-mcp-status false) state)]
|
||||||
|
(t/is (false? (get-in result [:profile :props :mcp-enabled]))))))
|
||||||
|
|
||||||
|
(t/deftest test-update-mcp-connection-status
|
||||||
|
(t/testing "sets connection status to connected"
|
||||||
|
(let [state {:mcp {:connection-status "disconnected"}}
|
||||||
|
result (ptk/update (mcp/update-mcp-connection-status "connected") state)]
|
||||||
|
(t/is (= "connected" (get-in result [:mcp :connection-status])))))
|
||||||
|
|
||||||
|
(t/testing "sets connection status to disconnected"
|
||||||
|
(let [state {:mcp {:connection-status "connected"}}
|
||||||
|
result (ptk/update (mcp/update-mcp-connection-status "disconnected") state)]
|
||||||
|
(t/is (= "disconnected" (get-in result [:mcp :connection-status]))))))
|
||||||
|
|
||||||
|
(t/deftest test-init-sets-active
|
||||||
|
(t/testing "init sets :mcp :active to true"
|
||||||
|
(let [state {:mcp {:active false}}
|
||||||
|
result (ptk/update (mcp/init) state)]
|
||||||
|
(t/is (true? (get-in result [:mcp :active]))))))
|
||||||
@ -6,9 +6,18 @@
|
|||||||
|
|
||||||
(ns frontend-tests.data.workspace-thumbnails-test
|
(ns frontend-tests.data.workspace-thumbnails-test
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.thumbnails :as thc]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.thumbnails :as thumbnails]
|
[app.main.data.workspace.thumbnails :as thumbnails]
|
||||||
[cljs.test :as t :include-macros true]))
|
[beicon.v2.core :as rx]
|
||||||
|
[cljs.test :as t :include-macros true]
|
||||||
|
[frontend-tests.helpers.mock :as mock]
|
||||||
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
;; The qualified keyword used internally by app.main.data.workspace.thumbnails
|
||||||
|
;; for tracking the pending deletion queue in application state.
|
||||||
|
(def ^:private deletion-queue-key
|
||||||
|
:app.main.data.workspace.thumbnails/thumbnails-deletion-queue)
|
||||||
|
|
||||||
(t/deftest extract-frame-changes-handles-cyclic-frame-links
|
(t/deftest extract-frame-changes-handles-cyclic-frame-links
|
||||||
(let [page-id (uuid/next)
|
(let [page-id (uuid/next)
|
||||||
@ -33,4 +42,257 @@
|
|||||||
:component-root true}}}}}]
|
:component-root true}}}}}]
|
||||||
(t/is (= #{["frame" root-id]
|
(t/is (= #{["frame" root-id]
|
||||||
["component" shape-b-id]}
|
["component" shape-b-id]}
|
||||||
(#'thumbnails/extract-frame-changes page-id [event [old-data new-data]])))))
|
(#'thumbnails/extract-frame-changes page-id [event [old-data new-data]]))))
|
||||||
|
|
||||||
|
;; --- Batch deletion queue state management ---
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-adds-to-deletion-queue
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
object-id (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
uri "blob:http://localhost/test-thumb"
|
||||||
|
event (thumbnails/clear-thumbnail file-id object-id)
|
||||||
|
state {:thumbnails {object-id uri}}
|
||||||
|
result (ptk/update event state)]
|
||||||
|
;; Thumbnail removed from the map
|
||||||
|
(t/is (nil? (get-in result [:thumbnails object-id])))
|
||||||
|
;; Object-id added to the deletion queue with its URI
|
||||||
|
(t/is (= uri (get-in result [deletion-queue-key object-id])))))
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-keeps-other-thumbnails
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
object-id1 (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
object-id2 (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
uri1 "blob:http://localhost/thumb-1"
|
||||||
|
uri2 "blob:http://localhost/thumb-2"
|
||||||
|
event (thumbnails/clear-thumbnail file-id object-id1)
|
||||||
|
state {:thumbnails {object-id1 uri1 object-id2 uri2}}
|
||||||
|
result (ptk/update event state)]
|
||||||
|
;; Only the cleared thumbnail is removed
|
||||||
|
(t/is (nil? (get-in result [:thumbnails object-id1])))
|
||||||
|
(t/is (= uri2 (get-in result [:thumbnails object-id2])))
|
||||||
|
;; Only the cleared thumbnail is queued
|
||||||
|
(t/is (= uri1 (get-in result [deletion-queue-key object-id1])))
|
||||||
|
(t/is (nil? (get-in result [deletion-queue-key object-id2])))))
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-accumulates-in-queue
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
object-id1 (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
object-id2 (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
uri1 "blob:http://localhost/thumb-1"
|
||||||
|
uri2 "blob:http://localhost/thumb-2"
|
||||||
|
event1 (thumbnails/clear-thumbnail file-id object-id1)
|
||||||
|
event2 (thumbnails/clear-thumbnail file-id object-id2)
|
||||||
|
state {:thumbnails {object-id1 uri1 object-id2 uri2}}
|
||||||
|
state1 (ptk/update event1 state)
|
||||||
|
state2 (ptk/update event2 state1)]
|
||||||
|
;; Both removed from thumbnails
|
||||||
|
(t/is (nil? (get-in state2 [:thumbnails object-id1])))
|
||||||
|
(t/is (nil? (get-in state2 [:thumbnails object-id2])))
|
||||||
|
;; Both accumulated in the queue
|
||||||
|
(t/is (= uri1 (get-in state2 [deletion-queue-key object-id1])))
|
||||||
|
(t/is (= uri2 (get-in state2 [deletion-queue-key object-id2])))
|
||||||
|
(t/is (= 2 (count (get state2 deletion-queue-key))))))
|
||||||
|
|
||||||
|
(t/deftest remove-from-deletion-queue-removes-entry
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
object-id (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
event (thumbnails/remove-from-deletion-queue object-id)
|
||||||
|
state {deletion-queue-key {object-id "blob:http://localhost/thumb"}}
|
||||||
|
result (ptk/update event state)]
|
||||||
|
(t/is (nil? (get-in result [deletion-queue-key object-id])))
|
||||||
|
(t/is (empty? (get result deletion-queue-key)))))
|
||||||
|
|
||||||
|
(t/deftest remove-from-deletion-queue-keeps-other-entries
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
object-id1 (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
object-id2 (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
uri1 "blob:http://localhost/thumb-1"
|
||||||
|
uri2 "blob:http://localhost/thumb-2"
|
||||||
|
event (thumbnails/remove-from-deletion-queue object-id1)
|
||||||
|
state {deletion-queue-key {object-id1 uri1
|
||||||
|
object-id2 uri2}}
|
||||||
|
result (ptk/update event state)]
|
||||||
|
;; Only the specified entry is removed
|
||||||
|
(t/is (nil? (get-in result [deletion-queue-key object-id1])))
|
||||||
|
(t/is (= uri2 (get-in result [deletion-queue-key object-id2])))
|
||||||
|
(t/is (= 1 (count (get result deletion-queue-key))))))
|
||||||
|
|
||||||
|
(t/deftest remove-before-clear-cancels-pending-delete
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
object-id (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
uri "blob:http://localhost/thumb"
|
||||||
|
;; Step 1: clear-thumbnail queues the delete
|
||||||
|
state1 (ptk/update (thumbnails/clear-thumbnail file-id object-id)
|
||||||
|
{:thumbnails {object-id uri}})
|
||||||
|
;; Step 2: remove-from-deletion-queue cancels the pending delete
|
||||||
|
state2 (ptk/update (thumbnails/remove-from-deletion-queue object-id)
|
||||||
|
state1)]
|
||||||
|
;; Thumbnail was removed from :thumbnails map by clear-thumbnail
|
||||||
|
(t/is (nil? (get-in state2 [:thumbnails object-id])))
|
||||||
|
;; But the deletion queue entry was cancelled by remove-from-deletion-queue
|
||||||
|
(t/is (nil? (get-in state2 [deletion-queue-key object-id])))
|
||||||
|
(t/is (empty? (get state2 deletion-queue-key)))))
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-batch-drains-queue
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
object-id1 (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
object-id2 (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
uri1 "blob:http://localhost/thumb-1"
|
||||||
|
uri2 "blob:http://localhost/thumb-2"
|
||||||
|
;; Build up the queue state manually (simulating accumulated clear-thumbnails)
|
||||||
|
state {deletion-queue-key {object-id1 uri1 object-id2 uri2}}
|
||||||
|
event (#'thumbnails/clear-thumbnail-batch)
|
||||||
|
result (ptk/update event state)]
|
||||||
|
;; The queue is drained from application state
|
||||||
|
(t/is (empty? (get result deletion-queue-key)))))
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-batch-empty-queue-noop
|
||||||
|
(let [state {deletion-queue-key {}}
|
||||||
|
event (#'thumbnails/clear-thumbnail-batch)
|
||||||
|
result (ptk/update event state)]
|
||||||
|
;; State unchanged when queue is already empty
|
||||||
|
(t/is (empty? (get result deletion-queue-key)))
|
||||||
|
(t/is (= state (dissoc result deletion-queue-key)))))
|
||||||
|
|
||||||
|
(t/deftest assoc-thumbnail-adds-to-map
|
||||||
|
(let [object-id (thc/fmt-object-id (uuid/next) (uuid/next) (uuid/next) "frame")
|
||||||
|
uri "blob:http://localhost/new-thumb"
|
||||||
|
event (#'thumbnails/assoc-thumbnail object-id uri)
|
||||||
|
state {:thumbnails {}}
|
||||||
|
result (ptk/update event state)]
|
||||||
|
(t/is (= uri (get-in result [:thumbnails object-id])))))
|
||||||
|
|
||||||
|
(t/deftest duplicate-thumbnail-copies-entry
|
||||||
|
(let [old-id (thc/fmt-object-id (uuid/next) (uuid/next) (uuid/next) "frame")
|
||||||
|
new-id (thc/fmt-object-id (uuid/next) (uuid/next) (uuid/next) "frame")
|
||||||
|
uri "blob:http://localhost/dup-thumb"
|
||||||
|
event (thumbnails/duplicate-thumbnail old-id new-id)
|
||||||
|
state {:thumbnails {old-id uri}}
|
||||||
|
result (ptk/update event state)]
|
||||||
|
(t/is (= uri (get-in result [:thumbnails old-id])))
|
||||||
|
(t/is (= uri (get-in result [:thumbnails new-id])))))
|
||||||
|
|
||||||
|
;; --- Async WatchEvent tests ---
|
||||||
|
|
||||||
|
(defn- make-obj-ids
|
||||||
|
"Helper to create n properly-formatted object-ids for a single file."
|
||||||
|
[file-id n]
|
||||||
|
(vec (repeatedly n #(thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame"))))
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-batch-watch-calls-rpc-with-object-ids
|
||||||
|
(t/async done
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
oids (make-obj-ids file-id 3)
|
||||||
|
state {deletion-queue-key (zipmap oids (repeat "blob:http://test"))}
|
||||||
|
event (#'thumbnails/clear-thumbnail-batch)]
|
||||||
|
(ptk/update event state)
|
||||||
|
(mock/with-mocks
|
||||||
|
{#'app.main.repo/cmd! mock/rpc-cmd!-mock
|
||||||
|
#'app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
||||||
|
(fn [done']
|
||||||
|
(->> (ptk/watch event state nil)
|
||||||
|
(rx/reduce conj [])
|
||||||
|
(rx/subs!
|
||||||
|
(fn [_] nil)
|
||||||
|
(fn [err] (t/is (nil? err)) (done'))
|
||||||
|
(fn [_]
|
||||||
|
(t/is (= 1 (count @mock/rpc-calls)))
|
||||||
|
(let [[{:keys [cmd params]}] @mock/rpc-calls]
|
||||||
|
(t/is (= :delete-file-object-thumbnails cmd))
|
||||||
|
(t/is (= (vec oids) (:object-ids params))))
|
||||||
|
(done')))))
|
||||||
|
done))))
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-batch-watch-partitions-large-batch
|
||||||
|
(t/async done
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
oids (make-obj-ids file-id 250)
|
||||||
|
state {deletion-queue-key (zipmap oids (repeat "blob:http://test"))}
|
||||||
|
event (#'thumbnails/clear-thumbnail-batch)]
|
||||||
|
(ptk/update event state)
|
||||||
|
(mock/with-mocks
|
||||||
|
{#'app.main.repo/cmd! mock/rpc-cmd!-mock
|
||||||
|
#'app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
||||||
|
(fn [done']
|
||||||
|
(->> (ptk/watch event state nil)
|
||||||
|
(rx/reduce conj [])
|
||||||
|
(rx/subs!
|
||||||
|
(fn [_] nil)
|
||||||
|
(fn [err] (t/is (nil? err)) (done'))
|
||||||
|
(fn [_]
|
||||||
|
(t/is (= 2 (count @mock/rpc-calls)))
|
||||||
|
(let [[c1 c2] @mock/rpc-calls]
|
||||||
|
(t/is (= :delete-file-object-thumbnails (:cmd c1)))
|
||||||
|
(t/is (= :delete-file-object-thumbnails (:cmd c2)))
|
||||||
|
(t/is (= 200 (count (:object-ids (:params c1)))))
|
||||||
|
(t/is (= 50 (count (:object-ids (:params c2)))))
|
||||||
|
(t/is (= (set oids)
|
||||||
|
(set (concat (:object-ids (:params c1))
|
||||||
|
(:object-ids (:params c2)))))))
|
||||||
|
(done')))))
|
||||||
|
done))))
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-batch-watch-revokes-blob-uris
|
||||||
|
(t/async done
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
oids (make-obj-ids file-id 2)
|
||||||
|
uris ["blob:http://localhost/thumb-1"
|
||||||
|
"blob:http://localhost/thumb-2"]
|
||||||
|
state {deletion-queue-key (zipmap oids uris)}
|
||||||
|
event (#'thumbnails/clear-thumbnail-batch)]
|
||||||
|
(ptk/update event state)
|
||||||
|
(mock/with-mocks
|
||||||
|
{#'app.main.repo/cmd! (fn [_ _] (rx/of nil))
|
||||||
|
#'app.util.webapi/revoke-uri mock/revoke-uri-mock
|
||||||
|
#'app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
||||||
|
(fn [done']
|
||||||
|
(->> (ptk/watch event state nil)
|
||||||
|
(rx/reduce conj [])
|
||||||
|
(rx/subs!
|
||||||
|
(fn [_] nil)
|
||||||
|
(fn [err] (t/is (nil? err)) (done'))
|
||||||
|
(fn [_]
|
||||||
|
(t/is (= (set uris) (set @mock/revoked-uris)))
|
||||||
|
(done')))))
|
||||||
|
done))))
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-batch-watch-empty-queue-no-rpc
|
||||||
|
(t/async done
|
||||||
|
(let [event (#'thumbnails/clear-thumbnail-batch)
|
||||||
|
state {}]
|
||||||
|
(ptk/update event state)
|
||||||
|
(mock/with-mocks
|
||||||
|
{#'app.main.repo/cmd! mock/rpc-cmd!-mock
|
||||||
|
#'app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
||||||
|
(fn [done']
|
||||||
|
(->> (ptk/watch event state nil)
|
||||||
|
(rx/reduce conj [])
|
||||||
|
(rx/subs!
|
||||||
|
(fn [_] nil)
|
||||||
|
(fn [err] (t/is (nil? err)) (done'))
|
||||||
|
(fn [_]
|
||||||
|
(t/is (empty? @mock/rpc-calls))
|
||||||
|
(done')))))
|
||||||
|
done))))
|
||||||
|
|
||||||
|
(t/deftest clear-thumbnail-watch-emits-batch-after-debounce
|
||||||
|
(t/async done
|
||||||
|
(let [file-id (uuid/next)
|
||||||
|
object-id (thc/fmt-object-id file-id (uuid/next) (uuid/next) "frame")
|
||||||
|
uri "blob:http://localhost/thumb"
|
||||||
|
state {:thumbnails {object-id uri}}
|
||||||
|
event (thumbnails/clear-thumbnail file-id object-id)]
|
||||||
|
(ptk/update event state)
|
||||||
|
(mock/with-mocks
|
||||||
|
{#'beicon.v2.core/timer mock/timer-mock}
|
||||||
|
(fn [done']
|
||||||
|
(->> (ptk/watch event state nil)
|
||||||
|
(rx/reduce conj [])
|
||||||
|
(rx/subs!
|
||||||
|
(fn [_] nil)
|
||||||
|
(fn [err] (t/is (nil? err)) (done'))
|
||||||
|
(fn [events]
|
||||||
|
(t/is (= 1 (count events)))
|
||||||
|
(t/is (ptk/event? (first events)))
|
||||||
|
(done')))))
|
||||||
|
done)))))
|
||||||
|
|||||||
103
frontend/test/frontend_tests/helpers/mock.cljs
Normal file
103
frontend/test/frontend_tests/helpers/mock.cljs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
;; 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 frontend-tests.helpers.mock
|
||||||
|
"Async-first mocking primitives for ClojureScript tests.
|
||||||
|
|
||||||
|
Uses `with-redefs` — the standard CLJS mechanism for rebinding Vars
|
||||||
|
within a dynamic scope. Recording atoms (`rpc-calls`, `revoked-uris`)
|
||||||
|
persist across the entire test lifecycle, making captured data
|
||||||
|
inspectable regardless of whether callbacks fire synchronously or
|
||||||
|
asynchronously.
|
||||||
|
|
||||||
|
The `with-mocks` helper wraps the lifecycle:
|
||||||
|
1. Reset recording atoms
|
||||||
|
2. Install mocks via `with-redefs`
|
||||||
|
3. Execute `(test-fn inner-done)`
|
||||||
|
4. `inner-done` calls `outer-done` (typically `cljs.test/async`'s done)
|
||||||
|
|
||||||
|
Since all mock functions return synchronous `rx/of` observables,
|
||||||
|
callbacks always fire within the `with-redefs` body."
|
||||||
|
(:require
|
||||||
|
[beicon.v2.core :as rx]))
|
||||||
|
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
;; Recording atoms
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
(def rpc-calls
|
||||||
|
"Atom accumulating mocked `rp/cmd!` calls as `{:cmd kw :params map}`."
|
||||||
|
(atom []))
|
||||||
|
|
||||||
|
(def revoked-uris
|
||||||
|
"Atom accumulating URIs passed to `wapi/revoke-uri`."
|
||||||
|
(atom []))
|
||||||
|
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
;; Mock implementations
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
(defn rpc-cmd!-mock
|
||||||
|
"Records [cmd params] in [[rpc-calls]], returns `(rx/of nil)`."
|
||||||
|
[cmd params]
|
||||||
|
(swap! rpc-calls conj {:cmd cmd :params params})
|
||||||
|
(rx/of nil))
|
||||||
|
|
||||||
|
(defn revoke-uri-mock
|
||||||
|
"Records `uri` in [[revoked-uris]]."
|
||||||
|
[uri]
|
||||||
|
(swap! revoked-uris conj uri))
|
||||||
|
|
||||||
|
(defn schedule-on-idle-mock
|
||||||
|
"Calls `f` immediately instead of deferring to the idle queue."
|
||||||
|
[f]
|
||||||
|
(f))
|
||||||
|
|
||||||
|
(defn timer-mock
|
||||||
|
"Returns `(rx/of :immediate)` so debounce timers fire instantly
|
||||||
|
during tests."
|
||||||
|
[_ms]
|
||||||
|
(rx/of :immediate))
|
||||||
|
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
;; Lifecycle
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
(defn reset!
|
||||||
|
"Clear all recording atoms. Called automatically by [[with-mocks]]."
|
||||||
|
[]
|
||||||
|
(reset! rpc-calls [])
|
||||||
|
(reset! revoked-uris []))
|
||||||
|
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
;; Public API
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
(defn with-mocks
|
||||||
|
"Resets recording atoms, installs `mocks` via `with-redefs`, then
|
||||||
|
calls `(test-fn inner-done)`.
|
||||||
|
|
||||||
|
`mocks` is a map of `Var → mock-fn` (e.g. `{#'rp/cmd! mock-fn}`).
|
||||||
|
`inner-done` tears down the `with-redefs` (by returning) and calls
|
||||||
|
`outer-done` (the `cljs.test/async` `done` callback).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
(t/deftest my-async-test
|
||||||
|
(t/async done
|
||||||
|
(mock/with-mocks
|
||||||
|
{#'rp/cmd! mock/rpc-cmd!-mock}
|
||||||
|
(fn [done']
|
||||||
|
(->> (some-async-flow)
|
||||||
|
(rx/subs!
|
||||||
|
(fn [v] ...)
|
||||||
|
(fn [err] (done'))
|
||||||
|
(fn [] (done'))))))))"
|
||||||
|
[mocks test-fn outer-done]
|
||||||
|
(reset!)
|
||||||
|
(apply with-redefs (mapcat identity mocks)
|
||||||
|
(test-fn (fn inner-done []
|
||||||
|
(outer-done)))))
|
||||||
@ -11,6 +11,7 @@
|
|||||||
[frontend-tests.data.uploads-test]
|
[frontend-tests.data.uploads-test]
|
||||||
[frontend-tests.data.viewer-test]
|
[frontend-tests.data.viewer-test]
|
||||||
[frontend-tests.data.workspace-colors-test]
|
[frontend-tests.data.workspace-colors-test]
|
||||||
|
[frontend-tests.data.workspace-mcp-test]
|
||||||
[frontend-tests.data.workspace-media-test]
|
[frontend-tests.data.workspace-media-test]
|
||||||
[frontend-tests.data.workspace-shortcuts-test]
|
[frontend-tests.data.workspace-shortcuts-test]
|
||||||
[frontend-tests.data.workspace-texts-test]
|
[frontend-tests.data.workspace-texts-test]
|
||||||
@ -63,6 +64,7 @@
|
|||||||
frontend-tests.data.uploads-test
|
frontend-tests.data.uploads-test
|
||||||
frontend-tests.data.viewer-test
|
frontend-tests.data.viewer-test
|
||||||
frontend-tests.data.workspace-colors-test
|
frontend-tests.data.workspace-colors-test
|
||||||
|
frontend-tests.data.workspace-mcp-test
|
||||||
frontend-tests.data.workspace-media-test
|
frontend-tests.data.workspace-media-test
|
||||||
frontend-tests.data.workspace-shortcuts-test
|
frontend-tests.data.workspace-shortcuts-test
|
||||||
frontend-tests.data.workspace-texts-test
|
frontend-tests.data.workspace-texts-test
|
||||||
|
|||||||
@ -4888,16 +4888,16 @@ msgid "onboarding.questions.team-size.just-me"
|
|||||||
msgstr "Just me"
|
msgstr "Just me"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.2-100"
|
msgid "onboarding.questions.team-size.2-100"
|
||||||
msgstr "2-100"
|
msgstr "2 - 100"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.101-500"
|
msgid "onboarding.questions.team-size.101-500"
|
||||||
msgstr "101-500"
|
msgstr "101 - 500"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.501-1000"
|
msgid "onboarding.questions.team-size.501-1000"
|
||||||
msgstr "501-1,000"
|
msgstr "501 - 1,000"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.1001-5000"
|
msgid "onboarding.questions.team-size.1001-5000"
|
||||||
msgstr "1,001-5,000"
|
msgstr "1,001 - 5,000"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.more-than-5001"
|
msgid "onboarding.questions.team-size.more-than-5001"
|
||||||
msgstr "5,001+"
|
msgstr "5,001+"
|
||||||
@ -9684,7 +9684,16 @@ msgstr "Create board. Click and drag to define its size. (%s)"
|
|||||||
msgid "workspace.toolbar.image"
|
msgid "workspace.toolbar.image"
|
||||||
msgstr "Image (%s)"
|
msgstr "Image (%s)"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/top_toolbar.cljs:139, src/app/main/ui/workspace/top_toolbar.cljs:140
|
msgid "workspace.toolbar.mcp"
|
||||||
|
msgstr "MCP"
|
||||||
|
|
||||||
|
msgid "workspace.toolbar.mcp-connected"
|
||||||
|
msgstr "MCP connected"
|
||||||
|
|
||||||
|
msgid "workspace.toolbar.mcp-connect-here"
|
||||||
|
msgstr "Connect here"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/top_toolbar.cljs:143
|
||||||
msgid "workspace.toolbar.move"
|
msgid "workspace.toolbar.move"
|
||||||
msgstr "Move (%s)"
|
msgstr "Move (%s)"
|
||||||
|
|
||||||
|
|||||||
@ -4757,16 +4757,16 @@ msgid "onboarding.questions.team-size.just-me"
|
|||||||
msgstr "Sólo yo"
|
msgstr "Sólo yo"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.2-100"
|
msgid "onboarding.questions.team-size.2-100"
|
||||||
msgstr "2-100"
|
msgstr "2 - 100"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.101-500"
|
msgid "onboarding.questions.team-size.101-500"
|
||||||
msgstr "101-500"
|
msgstr "101 - 500"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.501-1000"
|
msgid "onboarding.questions.team-size.501-1000"
|
||||||
msgstr "501-1000"
|
msgstr "501 - 1000"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.1001-5000"
|
msgid "onboarding.questions.team-size.1001-5000"
|
||||||
msgstr "1001-5000"
|
msgstr "1001 - 5000"
|
||||||
|
|
||||||
msgid "onboarding.questions.team-size.more-than-5001"
|
msgid "onboarding.questions.team-size.more-than-5001"
|
||||||
msgstr "5001+"
|
msgstr "5001+"
|
||||||
@ -9357,7 +9357,16 @@ msgstr "Crear tablero. Click y arrastrar para definir el tamaño. (%s)"
|
|||||||
msgid "workspace.toolbar.image"
|
msgid "workspace.toolbar.image"
|
||||||
msgstr "Imagen (%s)"
|
msgstr "Imagen (%s)"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/top_toolbar.cljs:139, src/app/main/ui/workspace/top_toolbar.cljs:140
|
msgid "workspace.toolbar.mcp"
|
||||||
|
msgstr "MCP"
|
||||||
|
|
||||||
|
msgid "workspace.toolbar.mcp-connected"
|
||||||
|
msgstr "MCP conectado"
|
||||||
|
|
||||||
|
msgid "workspace.toolbar.mcp-connect-here"
|
||||||
|
msgstr "Conectar aquí"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/top_toolbar.cljs:143
|
||||||
msgid "workspace.toolbar.move"
|
msgid "workspace.toolbar.move"
|
||||||
msgstr "Mover (%s)"
|
msgstr "Mover (%s)"
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@penpot/mcp",
|
"name": "@penpot/mcp",
|
||||||
"version": "2.16.0-rc.9.11",
|
"version": "2.16.0",
|
||||||
"description": "MCP server for Penpot integration",
|
"description": "MCP server for Penpot integration",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"author": "Kaleidos INC Sucursal en España SL",
|
"author": "Kaleidos INC Sucursal en España SL",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319",
|
"packageManager": "pnpm@11.6.0+sha512.9a36518224080c6fe5165afdcfe79bfa118c29be703f3f462b1e32efe1e98e47e8750b148e08286250aad4113cc7993ca413c4e2cd447752708c2ee5751bc95f",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/penpot/penpot"
|
"url": "https://github.com/penpot/penpot"
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
allowBuilds:
|
allowBuilds:
|
||||||
|
esbuild: true
|
||||||
opencode-ai: true
|
opencode-ai: true
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user