Compare commits

...

1126 Commits

Author SHA1 Message Date
Andrey Antukh
588dd5452a 📎 Start new development cycle for 2.5 2024-11-15 09:36:20 +01:00
Andrey Antukh
a02a316165 Merge remote-tracking branch 'origin/staging' into develop 2024-11-15 09:34:28 +01:00
Andrey Antukh
bbfcff0772 🐛 Update build data and version on all frontend templates
not only index.html
2024-11-14 18:48:48 +01:00
Andrey Antukh
6b9f7e9922 Merge pull request #5308 from penpot/alotor-fix-default-url-plugins
🐛 Fix default plugin list url
2024-11-14 18:21:56 +01:00
Andrey Antukh
21cdd1200a :paperlip: Add minor update to render-wasm build script 2024-11-14 18:18:22 +01:00
Andrey Antukh
aeda6271cd Improve release build process for render wasm 2024-11-14 18:14:43 +01:00
alonso.torres
63ee99d46c 🐛 Fix default plugin list url 2024-11-14 17:34:49 +01:00
Andrey Antukh
058c3707c8 Improve consistency on devenv initialization 2024-11-14 17:23:45 +01:00
Andrey Antukh
b81ffa422f 📎 Update devenv entrypoint 2024-11-14 14:38:40 +01:00
Andrey Antukh
e54f213b3f 🐛 Set a different cache directory for emcsdk 2024-11-14 14:29:19 +01:00
Andrey Antukh
97072b112c 🐛 Add another attempt to fix build related to render-wasm 2024-11-14 13:08:06 +01:00
Andrey Antukh
16ff29538b 🐛 Fix issue on frontend build script 2024-11-14 12:39:12 +01:00
Andrey Antukh
48b72229c3 📎 Add workaround for missing cargo on PATH on render-wasm build script 2024-11-14 12:36:43 +01:00
Andrey Antukh
fa8af898ba 🐛 Add cargo to PATH environment on devenv 2024-11-14 12:35:45 +01:00
Anonymous
42e4a4a2dd 🌐 Add translations for: Swedish.
Currently translated at 92.3% (1444 of 1563 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/sv/
2024-11-14 12:14:47 +01:00
Anonymous
e778bc8b18 🌐 Add translations for: Dutch.
Currently translated at 92.3% (1444 of 1563 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/nl/
2024-11-14 12:14:46 +01:00
Anonymous
6d60ca0474 🌐 Add translations for: Latvian.
Currently translated at 92.3% (1444 of 1563 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/lv/
2024-11-14 12:14:46 +01:00
Anonymous
41f906110e 🌐 Add translations for: Ukrainian (ukr_UA).
Currently translated at 85.6% (1338 of 1563 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
2024-11-14 12:14:46 +01:00
Anonymous
8d7be1e273 🌐 Add translations for: Czech.
Currently translated at 92.1% (1440 of 1563 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/cs/
2024-11-14 12:14:46 +01:00
Anonymous
13adc88637 🌐 Add translations for: Hebrew.
Currently translated at 92.3% (1444 of 1563 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
2024-11-14 12:14:46 +01:00
Anonymous
84f063a5b4 🌐 Add translations for: Indonesian.
Currently translated at 92.3% (1444 of 1563 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/id/
2024-11-14 12:14:46 +01:00
Anonymous
647357a892 🌐 Add translations for: German.
Currently translated at 91.5% (1431 of 1563 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-11-14 12:14:46 +01:00
Anonymous
c1eed3a364 🌐 Add translations for: Turkish.
Currently translated at 92.3% (1444 of 1563 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/tr/
2024-11-14 12:14:46 +01:00
Andrey Antukh
2dd7f241d3 Merge pull request #5303 from penpot/qol-feature-versions-plugins
 Add versions support in plugins
2024-11-14 12:14:22 +01:00
Alejandro
66c6e0232e Merge pull request #5301 from penpot/niwinz-binfile-v3-finetuning
🐛 Fix pending tasks and issues on binfile-v3 format
2024-11-14 12:12:48 +01:00
alonso.torres
4de43b32e8 Add versions support in plugins 2024-11-14 12:02:15 +01:00
Andrey Antukh
1d735e5b12 📎 Resync translation files
Mainly update translation string location comments on all locale files
2024-11-14 12:01:31 +01:00
Andrey Antukh
15d3107c48 Adapt workspace main menu to binfile-v3 config flag 2024-11-14 12:01:31 +01:00
Andrey Antukh
2d1158efa3 🐛 Fix issue with encoding/decoding thumbnails on binfile-v3 format 2024-11-14 11:45:11 +01:00
Andrey Antukh
f78f843f7c Use .penpot extension for binfile-v3 export format 2024-11-14 11:45:08 +01:00
Alejandro
07e40e78cd Merge pull request #5304 from penpot/niwinz-minor-improvements-renderer
 Make workspace and features system aware of render.wasm loading
2024-11-14 11:40:01 +01:00
Andrey Antukh
57f5e3c30a Merge branch 'translations' into develop 2024-11-14 11:36:09 +01:00
Andrey Antukh
32cd388b06 📎 Rehash and sort translation files 2024-11-14 11:35:28 +01:00
Andrey Antukh
d3829ec630 Merge remote-tracking branch 'weblate/develop' into translations 2024-11-14 11:32:50 +01:00
Andrey Antukh
1be204e22d Add render.wasm to the frontend build process 2024-11-14 11:20:39 +01:00
Andrey Antukh
5d4511fc6a Make workspace and features system aware of render.wasm loading 2024-11-14 11:20:39 +01:00
Alejandro
dd1997e23c Merge pull request #5302 from penpot/niwinz-develop-hotfix-1
🐛 Relax ldap provider requirements
2024-11-14 09:49:49 +01:00
Andrey Antukh
36914d1dc4 🐛 Relax ldap provider requirements 2024-11-14 09:40:38 +01:00
Andrey Antukh
1fdc724761 Merge pull request #5294 from penpot/superalex-feature-flag-for-render-wasm
🎉 Add feature flag for wasm render
2024-11-14 08:59:48 +01:00
Alejandro
3c6403224d Merge pull request #5267 from penpot/niwinz-backend-update-integrant
♻️ Update integrant to latest version
2024-11-14 07:50:49 +01:00
Andrey Antukh
88fb5e7ab5 ♻️ Update integrant to latest version
This upgrade also includes complete elimination of use spec
from the backend codebase, completing the long running migration
to fully use malli for validation and decoding.
2024-11-13 19:09:19 +01:00
Pablo Alba
8ed508012e Merge pull request #5290 from penpot/niwinz-team-request-access-bugfix
🐛 Several bugfixes related to the request-access feature
2024-11-13 14:37:48 +01:00
Belén Albeza
58d744a342 Merge pull request #5295 from penpot/superalex-refactor-naming-anidated-shapes-wasm
🎉 Refactor naming anidated shapes with children for wasm render
2024-11-13 14:26:57 +01:00
Andrey Antukh
8f72d8583e Merge pull request #5296 from penpot/palba-bugs-viewer-role
Bugs viewer role
2024-11-13 14:17:29 +01:00
Andrey Antukh
57d7dfaa0a Add final adjustements for binfile-v3 feature 2024-11-13 14:16:21 +01:00
Andrey Antukh
4f4ef6f1f2 Refresh members after accept team request access 2024-11-13 14:16:21 +01:00
Andrey Antukh
6eadea8485 Improve multi-input initial value handling
And removes the hard coupling of invite-email from it
2024-11-13 14:16:21 +01:00
Andrey Antukh
607e0c5c1d Move team invitations and access requests to a separate namespace
This commit also comes with:

- a fix for incorrect conflict handling on team access request creation
- a fix for incorrect handling of file-data when it is offloaded
- replace some inneficient queries with effcient ones
- remove redundant validation on creation of request-access
2024-11-13 14:16:18 +01:00
Pablo Alba
e31b4b58ce 🐛 Fix viewer role can use shortcut for create project 2024-11-13 14:03:07 +01:00
Alejandro
e659b8eb6e Merge pull request #5298 from penpot/niwinz-update-changelog
📎 Add missing breaking change notification on changelog
2024-11-13 13:36:18 +01:00
Andrey Antukh
962408c1ae 📎 Add missing breaking change notification on changelog
About the redis version pinning to version 7.2
2024-11-13 13:35:55 +01:00
Alejandro Alonso
c1d213a0cd 🎉 Refactor naming anidated shapes with children for wasm render 2024-11-13 13:35:28 +01:00
Alejandro
7e5115ecd9 Merge pull request #5293 from penpot/ladybenko-9265-solid-fills
Draw solid rect fills
2024-11-13 13:12:19 +01:00
Belén Albeza
539d5dfc08 🎉 Draw solid fills for shapes 2024-11-13 13:05:42 +01:00
Andrey Antukh
343f63a7cc Merge remote-tracking branch 'origin/staging' into develop 2024-11-13 12:54:22 +01:00
Alejandro Alonso
e3268739ed 🎉 Add feature flag for wasm render 2024-11-13 12:50:09 +01:00
Andrey Antukh
df416af19b Merge pull request #5280 from penpot/palba-enhancements-viewer-role
Enhancements for viewer role
2024-11-13 12:50:09 +01:00
Andrey Antukh
c0f026c332 💄 Add minor cosmetic changes to verify-token ns 2024-11-13 12:37:36 +01:00
Andrey Antukh
6b7665947e Merge branch 'ElenaMLopez-patch-1' into staging 2024-11-13 12:35:21 +01:00
Elena Mateos López
4f7659fbf8 📚 Update frontend.md
Fix a typo from `comonents` to `components` in the UI namespaces section, at settings.  :)
2024-11-13 12:34:58 +01:00
Pablo Alba
d4cf817b83 🐛 Fix libraries and templates section is shown for viewer role 2024-11-13 11:50:09 +01:00
Belén Albeza
669bca5fa5 ♻️ Remove unneeded display list for shapes 2024-11-13 10:59:03 +01:00
Belén Albeza
49b4eabe8b 🐛 Fix transform matrix being carried to non-children shapes 2024-11-13 10:57:14 +01:00
Andrey Antukh
03acfc2b3c Merge pull request #5289 from penpot/superalex-recurisve-wasm-drawing-shapes
🎉 Recursive drawing shapes in rust
2024-11-13 09:56:40 +01:00
Alejandro
d2f30d2b12 Merge pull request #5292 from penpot/palba-revert-open-modal-extra-event
Revert " Send event when an user opens a modal"
2024-11-13 09:34:32 +01:00
Pablo Alba
ccaadeb582 Revert " Send event when an user opens a modal"
This reverts commit 70a1a7a5ea.
2024-11-13 09:30:56 +01:00
Alejandro Alonso
b149f96500 🎉 Recursive drawing shapes in rust 2024-11-13 07:45:47 +01:00
Belén Albeza
132b1800c2 Merge pull request #5286 from penpot/superalex-render-modifiers
🎉 Save shape data in rust memory
2024-11-12 15:06:20 +01:00
Alejandro Alonso
65ee2f9081 🎉 Save shape data in rust memory 2024-11-12 12:13:06 +01:00
Yaron Shahrabani
4faa9ddd8d 🌐 Add translations for: Hebrew.
Currently translated at 99.5% (1447 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
2024-11-12 12:00:39 +01:00
Andrey Antukh
48909dc3c4 Merge remote-tracking branch 'origin/staging' into develop 2024-11-12 11:38:24 +01:00
trungly1
f1941681ab 📚 Update getting-started.md 2024-11-12 11:36:31 +01:00
Andrey Antukh
72313c770c Merge pull request #5281 from penpot/ladybenko-9202-update-devenv
🔧 Add rustfmt to the devenv
2024-11-12 11:29:50 +01:00
Andrey Antukh
c05a69509e 🐛 Fix invalid return value on worker api when worker is not available
Mainly happens on tests
2024-11-12 11:25:16 +01:00
Andrey Antukh
44ffdc4f97 Merge pull request #5266 from penpot/hiru-merge-tokens
Update design tokens
2024-11-12 10:46:53 +01:00
Andrés Moya
5a6c2c5054 🎉 Merge design-tokens branch
commit b4440aad04
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Fri Nov 8 16:08:07 2024 +0100

    🔧 Fix wrong code in merge

commit 5fee74cea8
Merge: a34207634 4f845b5c4
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Fri Nov 8 12:38:59 2024 +0100

    Merge remote-tracking branch 'origin/develop' into token-studio-develop

commit 4f845b5c4d
Merge: fb3f74e74 960f095c1
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Fri Nov 8 12:38:34 2024 +0100

    Merge remote-tracking branch 'upstream/develop' into develop

commit a34207634b
Merge: a757556e9 2c4eb96ab
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Fri Nov 8 12:12:31 2024 +0100

    Merge pull request #328 from tokens-studio/fix-merge-issues

    [WIP] Restore style-dictionary prerelease

commit 2c4eb96ab1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Nov 8 12:03:58 2024 +0100

    Remove comment block

commit 424b930990
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Nov 8 11:59:08 2024 +0100

    Remove patch file

commit cfd291db5e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Nov 8 11:46:42 2024 +0100

    Restore default

commit c76569e4b7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Nov 8 11:40:31 2024 +0100

    Downgrade

commit 456da5a46e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Nov 8 10:16:29 2024 +0100

    🐛 Fix name on fnc crashing the process

commit 072cec7a22
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Nov 8 09:58:42 2024 +0100

    Add testing block

commit a757556e9c
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Nov 7 18:32:09 2024 +0100

    Revert "🐛 Fix import of tinycolor2"

    This reverts commit 8e4574888d.

commit 8e4574888d
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Nov 7 18:17:24 2024 +0100

    🐛 Fix import of tinycolor2

commit 78a1a615d9
Merge: a910f06b2 fb3f74e74
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Nov 7 14:07:58 2024 +0100

    Merge remote-tracking branch 'origin/develop' into token-studio-develop

commit fb3f74e74f
Merge: 20590a5d1 96f8832bc
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Nov 7 14:06:45 2024 +0100

    Merge remote-tracking branch 'upstream/develop' into develop

commit 20590a5d18
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Nov 7 14:02:55 2024 +0100

    🔧 fix

commit e9c32841a9
Merge: 040a94f71 33ff74e53
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Nov 7 13:49:11 2024 +0100

    Merge remote-tracking branch 'upstream/develop' into develop

commit a910f06b2f
Merge: b3b8121d6 3d99c2a5e
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Nov 6 16:26:19 2024 +0100

    Merge pull request #326 from tokens-studio/stroke-context-menu

    [WIP]  Allow setting stroke-color via context-menu

commit 3d99c2a5eb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Nov 6 15:43:20 2024 +0100

     Allow setting stroke-color via context-menu

commit 040a94f719
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Tue Nov 5 13:16:56 2024 +0100

    🔧 Disable tokens in dev env by default

commit b3b8121d60
Merge: 32865c41c a33e0a386
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Mon Nov 4 13:45:44 2024 +0100

    Merge pull request #320 from tokens-studio/fix-dot-rename

    🐛 Fix renaming token to other namespace not working

commit a33e0a386e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Nov 4 13:43:38 2024 +0100

    ♻️Ensure collection return

commit 32865c41c9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 30 08:49:30 2024 +0100

    ♻ Remove zip.js compability warning when starting shadow-cljs

commit 315431fd49
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Mon Nov 4 13:02:32 2024 +0100

    🔧 Update dependencies

commit b47c5f9e60
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Oct 31 15:18:39 2024 +0100

    🐛 Fix sidebar tabs when there are no design tokens

commit a1fd7a912e
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Wed Oct 30 10:52:08 2024 +0100

    🔧 Use bun only for dev env (is needed to run frontend tests)

commit 60761eec07
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 29 17:06:32 2024 +0100

    🐛 Fix renaming token to other namespace not working

commit 62b859b84e
Merge: bc3ab8981 4f7622cb9
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue Oct 29 16:27:25 2024 +0100

    Merge pull request #318 from tokens-studio/fix-delete-set

    🐛 When deleting set remove it from theme

commit 4f7622cb93
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 29 14:19:42 2024 +0100

    🐛 When deleting set remove it from theme

commit bc3ab8981e
Author: Eva Marco <evamarcod@gmail.com>
Date:   Fri Oct 25 14:54:00 2024 +0200

    ♻️ Review sets code and add DS components

commit bef648a63f
Merge: cd7763ca0 0923dcc43
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Mon Oct 28 09:06:34 2024 +0100

    Merge pull request #312 from tokens-studio/import-sd-2

     Import: Verify data with StyleDictionary

commit 0923dcc43f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Oct 25 14:40:14 2024 +0200

    ♻ Make `process-sd-tokens` more readable

commit cd7763ca08
Merge: a1c401594 0ff5df4b8
Author: Andrés Moya <hirunatan@hammo.org>
Date:   Thu Oct 24 14:50:56 2024 +0200

    Merge pull request #313 from tokens-studio/eva-review-themes

    ♻️  Review themes section

commit 0ff5df4b8d
Author: Eva Marco <evamarcod@gmail.com>
Date:   Wed Oct 23 16:28:30 2024 +0200

    ♻️ Review themes section

commit f5596b2b3f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Oct 24 10:13:03 2024 +0200

    🐛 Temporary fix for import on sets with groups (/ delimiter)

commit a1c401594c
Merge: 03ea5414b 52d8bed0f
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Oct 24 09:42:25 2024 +0200

    Merge pull request #314 from tokens-studio/fix/deployment

    Fix/deployment

commit 52d8bed0fc
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Oct 24 09:29:38 2024 +0200

    Remove all gimlet and custom workflow code

commit 66dce0e795
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 22 10:14:47 2024 +0200

     Detect reference errors when importing tokens

commit d3ded00bc6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 23 14:13:49 2024 +0200

    🐛 Fix text-editor missing from token tests

commit bf3880a21c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 23 10:05:24 2024 +0200

    🐛 Remove box shadow from supported tokens

commit 951f558d1f
Merge: fa8037c4b 03ea5414b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 23 12:05:58 2024 +0200

    Merge branch 'develop' into token-studio-develop

commit 7debdefa22
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Oct 21 16:03:19 2024 +0200

    🐛 Fix outdated notifications map

commit 03ea5414be
Author: Eva Marco <evamarcod@gmail.com>
Date:   Mon Oct 21 17:14:17 2024 +0200

    ♻️ Review create and edit modal

commit 31b5f5cefa
Author: Eva Marco <evamarcod@gmail.com>
Date:   Mon Oct 21 16:36:47 2024 +0200

    ♻️ Format code

commit 96af0f065d
Merge: 2bdbd81a1 77ba6c135
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Mon Oct 21 10:10:55 2024 +0200

    Merge pull request #310 from tokens-studio/fix-set-rename

    🐛 Keep selection when renaming set

commit 77ba6c135e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Oct 21 10:08:03 2024 +0200

    🐛 Keep selection when renaming set

commit fa8037c4b5
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Oct 17 17:40:25 2024 +0200

    Deploy

commit 2bdbd81a19
Merge: aaac7fb04 9fe4919a2
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Oct 17 17:11:05 2024 +0200

    Merge pull request #308 from tokens-studio/merge-develop-2

    Sync with upstream develop

commit 9fe4919a2b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Oct 17 17:04:19 2024 +0200

    Migrate msg -> ntf

commit 6af6dd1288
Merge: aaac7fb04 b4c2f2eca
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Oct 17 17:03:23 2024 +0200

    Merge branch 'develop' into token-studio-develop

commit aaac7fb041
Merge: 41dc6083c c6ed081a0
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Oct 17 16:41:54 2024 +0200

    Merge pull request #305 from tokens-studio/dtcg-import

    DTCG Tokens Import / Export

commit c6ed081a0b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Oct 10 13:08:35 2024 +0200

     Implement token import / export

commit 41dc6083cf
Merge: bbf5fce0c 85fee87bc
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Oct 10 12:41:38 2024 +0200

    Merge pull request #298 from tokens-studio/dnd

    Sets Drag & Drop

commit 85fee87bc4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 8 10:24:07 2024 +0200

    🎉 Token Sets dnd re-ordering

commit a85a7d2b2f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 8 17:09:58 2024 +0200

    🐛 Fix logic in oassoc-in-before wher top items couldn't be move to bottom

commit bbf5fce0c9
Merge: bc4969c25 07beef572
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Oct 9 13:21:38 2024 +0200

    Merge pull request #297 from tokens-studio/feature-flag

     Add feature flag for design tokens

commit 07beef5727
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 9 11:00:51 2024 +0200

    Remove $PENPOT_FLAGS from frontend deployment

commit 11c8fa468f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 9 10:30:59 2024 +0200

    Manually override ff flags

commit b0ec9034dc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 9 10:09:45 2024 +0200

    Enable FF for gimlet

commit 18e0948b0c
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Mon Oct 7 14:16:08 2024 +0200

     Add feature flag for design tokens

commit bc4969c25d
Merge: d58932c2e 2baa1aa73
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Oct 3 15:44:02 2024 +0200

    Merge pull request #296 from tokens-studio/fix-reference-color-preview

    Fix reference color preview

commit 2baa1aa734
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Oct 3 15:30:39 2024 +0200

    Show resolved color

commit b3e73b9abc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Oct 3 15:18:41 2024 +0200

    Move over helper

commit 5de1f450c1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Oct 3 15:14:38 2024 +0200

    Move over token value reference check function

commit d58932c2e5
Merge: 6f086326f 69cc9d02b
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Oct 3 13:26:27 2024 +0200

    Merge pull request #290 from tokens-studio/refactor-themes-sets

    Refactor themes sets

commit 69cc9d02ba
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 17:23:04 2024 +0200

    Cleanup: item->token

commit d097b5b179
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 17:10:26 2024 +0200

    Cleanup

commit 921f4a6660
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 17:10:07 2024 +0200

    Restore all logic tests

commit 1097c1f282
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 17:02:10 2024 +0200

    Restore apply overwrite

commit f9a49f82f8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 17:00:31 2024 +0200

    Restore apply-multiple

commit f2900c6519
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 16:57:53 2024 +0200

    Cleanup: Sort

commit 1df40ea07a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 16:57:20 2024 +0200

    Restore apply-tokens test

commit eceffda095
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 16:47:17 2024 +0200

    Added todo

commit e55f323d60
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 15:47:59 2024 +0200

    Fix tests

commit 2634388d09
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 14:37:24 2024 +0200

    Remove logging

commit fa6b8cb6de
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 14:31:56 2024 +0200

    Use d/nilf

commit 2b6075d1a2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 14:21:18 2024 +0200

    Cleanup

commit 306a5e5f85
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 14:20:27 2024 +0200

    Sets don't have a specific order inside themes

commit 5170d328bd
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 14:19:02 2024 +0200

    Fix docstring

commit 4a818d55c8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 14:18:49 2024 +0200

    Rename, fix docstring

commit bbdc9e95f7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 14:17:20 2024 +0200

    Add todo

commit b12d5938e0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 14:10:41 2024 +0200

    Replace generic arg name

commit 041e04dcb1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 14:09:51 2024 +0200

    Remove unneeded ->

commit a235327c3e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 11:33:14 2024 +0200

    Cleanup

commit 0ffcda404b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 11:09:52 2024 +0200

    Cleanup

commit 93cc8214fa
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 11:05:39 2024 +0200

    Fix border-radius and sizing panels

commit 845de5d885
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 10:52:48 2024 +0200

    Fix export

commit fdca6e4edf
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 10:46:55 2024 +0200

    Fix measures options

commit 028809f1d5
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 10:22:09 2024 +0200

    Cleanup

commit 053d0fc923
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 10:15:35 2024 +0200

    Cleanup function

commit 0b081d24e0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 10:03:34 2024 +0200

    Only show warning when string has /

commit 669594e3c1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 09:42:56 2024 +0200

    Cleanup

commit 57a133e09d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 09:42:49 2024 +0200

    Add ordered tokens test

commit 43e5367988
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Oct 2 09:42:42 2024 +0200

    Fix testing from cljs

commit fa3e2c90e6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 15:45:14 2024 +0200

    Fix renaming via context menu

commit 7418d1fa2c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 15:42:09 2024 +0200

    Dont support token set grouping for now

commit 3681678dc4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 14:40:05 2024 +0200

    Migrate token tests to tokens-lib

commit bca4ea3819
Merge: 9268b18e5 6f086326f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 12:58:26 2024 +0200

    Merge remote-tracking branch 'origin/token-studio-develop' into refactor-themes-sets

commit 9268b18e56
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 12:53:01 2024 +0200

    Fix edit button

commit f1f2767e2a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 12:49:03 2024 +0200

    Activating initial sets by adding them to the token theme

commit 5825fa656b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 09:56:03 2024 +0200

    Fix tests

commit 993df23624
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 09:55:58 2024 +0200

    Remove unneeded tests

commit 442732117b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 09:55:23 2024 +0200

    Disable logic tests for now (nee new setup)

commit 0d870610e1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Oct 1 09:14:54 2024 +0200

    Fix infer warnings in tokens test

commit 231baac31d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 16:41:51 2024 +0200

    Fix renaming token creating new token

commit 4b39b6970a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 16:26:26 2024 +0200

    Fix theme sets not being in order of the root order

commit c5173d2df8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 15:33:17 2024 +0200

    Remove hidden token theme when activating a theme

commit 0ea0834b1a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 15:21:15 2024 +0200

    Cleanup

commit bfa90d0347
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 15:18:26 2024 +0200

    Fix duplicate token event

commit b0d46e1767
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 15:15:05 2024 +0200

    Cleanup

commit 3182ff1e15
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 15:08:18 2024 +0200

    Cleanup

commit dc0a1c1555
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 15:07:22 2024 +0200

    Cleanup

commit 18d120bbaa
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 15:04:12 2024 +0200

    Fix token creation without set

commit c75ab61732
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 14:44:42 2024 +0200

    Fix renamed theme staying in active-themes

commit df8f67b5d3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 13:52:50 2024 +0200

    Update workspace tokens

commit 1194eb7c61
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 09:39:11 2024 +0200

    Remove unused functions

commit a49992a74e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 09:38:01 2024 +0200

    Fix token updating

commit 5d61ddb385
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 09:33:35 2024 +0200

    Fix property applying

commit a59e391b38
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 09:19:06 2024 +0200

    Fix token deletion menu

commit cfec4ae958
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 09:08:14 2024 +0200

    Cleanup

commit 99a3ed98c9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 08:46:31 2024 +0200

    Only load context menu when open

commit 8c58ed80ac
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 08:31:18 2024 +0200

    Fix id

commit 066ee9c489
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 30 08:23:22 2024 +0200

    Tokens in sidebar

commit cce4014fbe
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Sep 27 15:36:07 2024 +0200

    Fix token create

commit b7cedf219b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Sep 27 11:21:30 2024 +0200

    Cleanup

commit 93ed1ded17
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Sep 27 11:14:34 2024 +0200

    Token resolving on add fixed

commit 1d50bacfbc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 17:21:02 2024 +0200

    Fix set renaming not being updated in themes

commit 7c4cbe5265
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 16:40:38 2024 +0200

    Cleanup

commit 2f13814285
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 16:37:30 2024 +0200

    Cleanup

commit 9f2b96332c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 16:16:44 2024 +0200

    Fix up active themes tokens method

commit 577fa2bc81
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 15:38:36 2024 +0200

    Cleanup

commit c8494c9931
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 15:32:46 2024 +0200

    Remove unused

commit 3843253a5d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 15:27:16 2024 +0200

    Dont render starting slash

commit 5f6a76dfce
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 15:24:02 2024 +0200

    Use currently active sets as sets for temporary theme

commit 29a2478bb5
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 15:15:50 2024 +0200

    Fix theme group drop-down not updating group value

commit b3ff480e81
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 15:08:54 2024 +0200

    Hide temporary theme

commit 2104fc04df
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 14:28:27 2024 +0200

    Fix theme select

commit 9c97b31d28
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 13:21:53 2024 +0200

    Fix theme creation/editing

commit 895f92e7c2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 12:03:03 2024 +0200

    Hide temporary token theme from user

commit e216d84484
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 26 11:28:14 2024 +0200

    Set toggling without a theme

commit 6f086326f5
Merge: 2f4a012be c755b764a
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Sep 25 16:22:20 2024 +0200

    Merge pull request #289 from tokens-studio/revert-288-active-themes

    Revert "Adds `active-themes` to `TokensLib`"

commit c755b764a2
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Sep 25 16:21:53 2024 +0200

    Revert "Adds `active-themes` to `TokensLib`"

commit 0b2b8a71fb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 25 15:08:52 2024 +0200

    Token deletion

commit 9c1a509fa4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 25 14:59:20 2024 +0200

    Set renaming

commit d2ed6b5501
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 25 14:45:31 2024 +0200

    Add set

commit 2f4a012beb
Merge: fb38e4378 6d75993fd
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Sep 25 13:48:41 2024 +0200

    Merge pull request #288 from tokens-studio/active-themes

    Adds `active-themes` to `TokensLib`

commit 99e551925a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 25 11:08:54 2024 +0200

    Updates

commit 4d4c4355ad
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 25 08:33:34 2024 +0200

    Selection by name

commit ec96e7918d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 25 08:16:29 2024 +0200

    Token theme deletion

commit 844819a50c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 24 15:25:29 2024 +0200

    Activate themes via lib

commit 4c327f38ef
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 23 15:18:46 2024 +0200

    Replace sets

commit f5c122b0db
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Sep 20 14:42:48 2024 +0200

    Remove legacy

commit c6770f43c7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Sep 20 14:38:53 2024 +0200

    Move out of legacy

commit 43e5e78053
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Sep 20 14:35:47 2024 +0200

    Cleanup

commit f5249196f9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Sep 20 14:27:19 2024 +0200

    Sets sidebar

commit 501256f16b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Sep 20 09:34:54 2024 +0200

    Disable namespace loading info in console from shadow-cljs

commit 9b2993a344
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 19 16:22:47 2024 +0200

    Fix theme select

commit 191d957984
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 19 16:06:53 2024 +0200

    Use theme listing

commit 743f61f2cd
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 19 15:44:56 2024 +0200

    Adding themes

commit 7758e48c48
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 19 10:52:15 2024 +0200

    Add legacy macro

commit 80e8903754
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 19 10:26:17 2024 +0200

    Refactor: Use tokens-lib for getting tokens theme

commit 6d75993fd7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 24 14:24:35 2024 +0200

    Move theme-path impl to ITokenTheme

commit 49579d75c6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 24 13:42:56 2024 +0200

    Simplify as this

commit d7d974242e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 24 11:18:12 2024 +0200

    Add active-themes to data serialization tests

commit f2569a1c4a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 24 11:13:41 2024 +0200

    Cleanup

commit 44e4e85201
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 24 11:10:07 2024 +0200

    Add schema validation

commit 5e39f33bff
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 24 11:06:12 2024 +0200

    Rename with theme prefix

commit 416297d298
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 23 17:37:16 2024 +0200

    Implement active-themes

commit fb38e4378a
Merge: 1a9d703bb 5b7b343f6
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Sep 18 18:10:42 2024 +0200

    Merge pull request #273 from tokens-studio/color-token

    Color token

commit 5b7b343f62
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 17:25:55 2024 +0200

    Cleanup

commit f5b62a5fc1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 17:23:42 2024 +0200

    Style the form to fit the color ramp exactly

commit 8804d1432e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 17:15:45 2024 +0200

    Update the input field value when chosing color from color ramp

commit 6084c49582
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 17:03:18 2024 +0200

    Share color picker effect to set hue slider css variables

commit 2a3fc9e7bd
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 17:03:08 2024 +0200

    Pointer

commit 061cd08e66
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 11:43:35 2024 +0200

    Remove unused functions

commit 48a8b1bc55
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 11:30:32 2024 +0200

    Fix color updating

commit c007170603
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 11:28:31 2024 +0200

    Cleanup

commit b68e7af844
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 11:27:30 2024 +0200

    Use tinycolor to convert hex color

commit e0e7b98ed7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 11:21:43 2024 +0200

    Docstring

commit 3bd2278dec
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 11:15:11 2024 +0200

    Use penpot logging system instead of custom debug flag

commit 77141887a8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 10:57:05 2024 +0200

    Pass in value with error

commit 3a21643158
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 10:38:16 2024 +0200

    Add shared error handling

commit 308fff05c3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 18 10:19:59 2024 +0200

    Dont show name error when editing new token and not touching name field

commit 49ff0df7f6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 17 16:35:08 2024 +0200

    Add tinycolor bindings

commit 3c4e0e2447
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 16 16:57:01 2024 +0200

    Add color ramp

commit ac51309f81
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Sep 16 15:59:04 2024 +0200

    Add placeholder color swatch

commit 2b886c54e0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 29 12:52:18 2024 +0200

    Color ramp wip

commit 0b29767c95
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 30 11:51:21 2024 +0200

    Add color token

commit 1a9d703bb1
Merge: 0697e6988 f0a9444ab
Author: Andrés Moya <hirunatan@hammo.org>
Date:   Wed Sep 18 11:00:06 2024 +0200

    Merge pull request #284 from tokens-studio/refactor-theme-groups

    tokens-lib refactor: Get collection of theme groups

commit f0a9444ab6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 17 10:48:23 2024 +0200

    tokens-lib refactor: Get collection of theme groups

commit 0697e69888
Merge: 1d7536687 0e15da5ed
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue Sep 17 09:44:00 2024 +0200

    Merge pull request #283 from tokens-studio/refactor-types-2

    Refactor types 2

commit 0e15da5ede
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Tue Sep 17 00:51:33 2024 +0200

    🔧 Make tokens again a flat ordered map

commit 5f703d6a79
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Mon Sep 16 17:47:05 2024 +0200

    🔧 Make themes a two-level only tree

commit 3a4ec32f8e
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Sep 12 10:04:03 2024 +0200

    🔧 add groups handling v2

commit e2ff6f7ba6
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Sep 5 17:51:02 2024 +0200

    🔧 Add first draft of token set groups attributes

commit fa8f8ac54b
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Thu Sep 5 16:49:29 2024 +0200

    🔧 add groups handling

commit 316d333c96
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Wed Sep 4 02:00:31 2024 +0200

    🔧 Add token themes in tokens-lib custom type

commit 1d7536687a
Merge: 6cba685e8 27073e22e
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Sep 12 17:27:39 2024 +0200

    Merge pull request #282 from tokens-studio/enable-ff

    Enable sets/themes for all

commit 6cba685e87
Merge: 6f37a43be a1e4d6b3b
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Sep 12 13:17:26 2024 +0200

    Merge pull request #281 from tokens-studio/token-refactor-common

    Fixes missing name attribute

commit 27073e22e3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 12 13:16:35 2024 +0200

    Enable sets/themes for all

commit a1e4d6b3b3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 12 10:36:05 2024 +0200

    Fix context menu missing name param

commit 309476fdfd
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Sep 12 10:23:45 2024 +0200

    Cleanup

commit 6f37a43be1
Merge: 361b02a76 0dca04733
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Sep 11 15:35:45 2024 +0200

    Merge pull request #262 from tokens-studio/refactor-types-1

    🔧 Add tokens-lib custom type

commit 361b02a76a
Merge: 1568a7afb 0cd7d4dd7
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Sep 11 15:11:22 2024 +0200

    Merge pull request #279 from tokens-studio/fix-inspect-tokens-tab

    Disable tokens tab in inspect mode

commit 1568a7afb5
Merge: f5ab6e65f 20e2c4edb
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Sep 11 15:11:02 2024 +0200

    Merge pull request #278 from tokens-studio/fix-set-token-name

    Allow giving name of tokens in other sets

commit 0cd7d4dd7a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 11 11:09:06 2024 +0200

    Disable tokens tab in inspect mode

commit f5ab6e65fc
Merge: 012e79603 56374171d
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Sep 11 11:02:55 2024 +0200

    Merge pull request #277 from tokens-studio/group-select-themes

    Themes & Sets: Add groups select to modal

commit 20e2c4edb1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Sep 11 10:17:46 2024 +0200

    Allow giving name of tokens in other sets

commit 012e79603f
Merge: 27409f43d 9876c2e4f
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Sep 11 09:09:51 2024 +0200

    Merge pull request #276 from tokens-studio/token-sets-context-menu

    Token Sets & Themes: Sets context menu

commit 56374171d6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 10 15:44:11 2024 +0200

    Fix theme groups not showing up in create state

commit 281b801112
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 10 15:42:44 2024 +0200

    Show dropdown only when groups exist

commit 21f42021d8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 10 15:37:01 2024 +0200

    Add groups select

commit df16d0c222
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 10 15:16:52 2024 +0200

    Add abstract dropdown component

commit d54c5476d8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 10 14:33:45 2024 +0200

    Add dropdown button

commit 9876c2e4fc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Sep 10 12:51:07 2024 +0200

    Add context menu

commit 0dca047339
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Tue Sep 3 14:20:55 2024 +0200

    fix token update

commit d147d844fb
Author: Andrés Moya <andres.moya@kaleidos.net>
Date:   Fri Aug 16 12:11:18 2024 +0200

    🔧 Add tokens-lib custom type

commit 27409f43d2
Merge: 734acd27b ae5aaf833
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Fri Aug 30 11:15:31 2024 +0200

    Merge pull request #264 from tokens-studio/token-sets-themes-ui

    Token sets themes UI

commit ae5aaf8332
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 29 16:02:22 2024 +0200

    Cleanup

commit 54b754c38c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 29 16:01:31 2024 +0200

    Cleanup

commit ca611c6668
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 29 15:59:58 2024 +0200

    Cleanup

commit 6bae2efe9d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 29 14:26:11 2024 +0200

    Validate against names in all token sets

commit 734acd27b9
Merge: 93ce6b6eb 1ed6d92d8
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue Aug 27 17:09:47 2024 +0200

    Merge pull request #263 from tokens-studio/token-sets-themes

    Token sets themes

commit e363b58774
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 15:22:02 2024 +0200

    HACK: Fix empty sets showing up in listing

commit b24b178e29
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 15:00:15 2024 +0200

    Make resizable

commit d6823e8583
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 14:49:11 2024 +0200

    Always switch to temporary theme when toggling sets in sidebar

commit 3bb99e8f7c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 14:37:24 2024 +0200

    Remove default theme name, disable empty themen name submit

commit 3b7432a859
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 14:32:26 2024 +0200

    Use non editable context in form

commit 4dd3367bdd
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 14:26:06 2024 +0200

    Allow creating token sets

commit d4910ce2fc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 14:25:52 2024 +0200

    Auto select new token sets

commit 4f96550bca
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 14:13:29 2024 +0200

    Use context

commit db22beb857
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 10:20:38 2024 +0200

    Fix iterating over unordered sets

commit 965016b63f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 27 10:04:12 2024 +0200

    Allow token renaming

commit 293250a30d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 16:35:49 2024 +0200

    Rename

commit 1d599cbf7d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 16:33:07 2024 +0200

    Always render ungroupd themes first

commit 0d2d1a8b8a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 16:23:23 2024 +0200

    Link up actions

commit cb46e11162
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 16:14:27 2024 +0200

    Add edit button

commit c807baaf7a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 15:54:44 2024 +0200

    Add custom select with grouped options

commit f25db592a0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 15:07:58 2024 +0200

    Clone over select

commit 2e23543c11
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 15:04:45 2024 +0200

    Show create text when no theme is available

commit 4060b6d40f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 15:02:38 2024 +0200

    Style empty state, jump to create theme dialog when no themes exist

commit 7cd9c60fb6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 14:36:00 2024 +0200

    Disable user-selection

commit 5939db771e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 14:34:41 2024 +0200

    Link up delete button & fix create theme ui jumping

commit 1405720e0b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 14:32:21 2024 +0200

    Cleanup

commit b5e08c5b8b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 14:32:01 2024 +0200

    Add theme creation form

commit f37cf8be5e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 14:31:34 2024 +0200

    Add defaults for theme form

commit 84b5be5547
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 14:17:37 2024 +0200

    Fix button being chosen as main button for form submit

commit 7aff690e7b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 14:17:30 2024 +0200

    Wire up theme updating

commit 70b570f112
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 13:49:57 2024 +0200

    Show only on create

commit 36f92aa241
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 13:47:44 2024 +0200

    Allow group and name updating

commit a0dd3f63bf
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 13:41:02 2024 +0200

    Allow controlling state of theme editing

commit fe702988f9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 26 13:40:49 2024 +0200

    Cleanup

commit 12e915dec8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 17:48:43 2024 +0200

    Style edit button

commit a52e20f49d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 17:22:05 2024 +0200

    Cleanup

commit 967fab416a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 17:20:20 2024 +0200

    Add back button

commit 3ce2531b42
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 17:11:38 2024 +0200

    Design

commit db1250a315
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 17:07:47 2024 +0200

    Add footer buttons

commit 6f7b69c7ee
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 16:58:49 2024 +0200

    Allow toggling individual set themes

commit 7e7203eb7c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 16:44:11 2024 +0200

    Allow passing custom functions

commit 8a20e3a698
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 16:34:33 2024 +0200

    Allow tokens sets component to be controlled

commit 1c0233098d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 16:28:06 2024 +0200

    Add sets list for theme

commit c7fa0f2cf8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 16:27:42 2024 +0200

    Cleanup

commit cac421f862
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 15:41:32 2024 +0200

    Design

commit 7970440ffc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 15:30:17 2024 +0200

    Toggle theme via ui

commit cc7de14539
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 15:08:53 2024 +0200

    Add basic toggle switch

commit d23c5cbbbe
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 14:53:22 2024 +0200

    Move the temporary ui to modal

commit b62722bdbb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 14:11:13 2024 +0200

    Add themes modal dialog

commit 1ed6d92d87
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 13:36:46 2024 +0200

    Remove margin

commit b48bfde5c8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 11:43:19 2024 +0200

    Automatically open when creating set

commit 1cc1d94a27
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 11:42:14 2024 +0200

    Automatically open when adding token

commit 40846b87c2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 11:39:13 2024 +0200

    Add tokens header

commit acc3606cbb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 11:36:54 2024 +0200

    Align Eye

commit 97f119f3da
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 11:32:54 2024 +0200

    Add delete set action button

commit 88c899c5c6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 10:17:52 2024 +0200

    Wrap themes ui in header

commit a9a5f69c93
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 10:15:37 2024 +0200

    Cleanup

commit bac16aadd8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 23 10:14:45 2024 +0200

    Migrate to official UI

commit b1cf641587
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 22 14:56:41 2024 +0200

    Fix cancelling set prompt breaking user state

commit e4f01d1d5e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 22 11:59:06 2024 +0200

    Fix logic

commit 157cc5a994
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 22 11:21:53 2024 +0200

    Automatically show themes and sets on dev and PR previews

commit 37a3fbcec2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 22 11:02:01 2024 +0200

    Fix not possible naming token to same token name in other set

commit 8343a9f3b5
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 22 10:59:40 2024 +0200

    Fix description

commit 4b47fa5d7a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 22 10:58:31 2024 +0200

    Fix names clash

commit 7a2a521075
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 22 10:54:41 2024 +0200

    Allow passing config

commit 6c802bc132
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 22 09:37:47 2024 +0200

    Rename

commit c130dc39c3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 19:11:53 2024 +0200

    Resolve tokens from other active sets

commit 8264da3a2a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 15:36:40 2024 +0200

    Use active sets tokens for form

commit 6c6be35292
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 15:12:13 2024 +0200

    Fix token updates not taking order

commit 011fc734f6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 14:42:39 2024 +0200

    Make passing of names-map explicit

commit 7c3716a709
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 11:18:52 2024 +0200

    Move temporary ui behind flag

commit 98207b02bf
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 11:18:47 2024 +0200

    Remove log

commit 0df89cf60d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 11:17:12 2024 +0200

    Use storage to toggle themes ui

commit 2df577cba2
Merge: 4e81a94d0 93ce6b6eb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 11:04:00 2024 +0200

    Merge remote-tracking branch 'origin/token-studio-develop' into token-sets-themes

commit 4e81a94d0f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 11:03:39 2024 +0200

    Remove unused functions

commit 4f02d8b47d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 11:01:23 2024 +0200

    Fix multi run test

commit 74801e72d3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 10:54:22 2024 +0200

    Fix simple token creation / scaffolding test

commit cfefbadb64
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 21 10:29:14 2024 +0200

    Fix id

commit 93ce6b6eb3
Merge: 9dd681c15 f9704fe7a
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 22:14:51 2024 +0530

    Merge pull request #256 from tokens-studio/token-sets-ui

    Token sets UI

commit f9704fe7aa
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 20 18:40:02 2024 +0200

    Fix padding without sets

commit 2487f34b72
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 21:34:07 2024 +0530

    formatting

commit b3e939d12a
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 21:30:59 2024 +0530

    add a hardcoded flag to display/hide token sets section

commit 247e3a1559
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 21:25:22 2024 +0530

    fix some styling issues

commit 5b1eaf4b8f
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 20:55:02 2024 +0530

    remove unused prop and some optimizations

commit 463ab3c866
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 20:41:25 2024 +0530

    change current-set to selected-set

commit 5358cd1c52
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 20 16:14:32 2024 +0200

    Fix tests crashing

commit 3a2f4df387
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 17:08:31 2024 +0530

    add source code comment

commit 1a3184d327
Merge: 187ab3166 9dd681c15
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 17:02:00 2024 +0530

    Merge branch 'token-studio-develop' into token-sets-ui

commit 187ab31667
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 17:00:19 2024 +0530

    format

commit feb5cec84b
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 16:57:53 2024 +0530

    ad sets-section wrapper

commit f052b75dac
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 16:38:18 2024 +0530

    formatting

commit e62323ac0a
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 16:35:33 2024 +0530

    add variable

commit d4c88d4441
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 16:32:36 2024 +0530

    remove folder open icon

commit 4bad9fa6f8
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 16:30:51 2024 +0530

    add chevron icon

commit e4f5b6005e
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 16:30:38 2024 +0530

    move sets-sidebar component to sidebar tokens

commit 98b5791e27
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 20 15:37:37 2024 +0530

    remove set-item-set-selected and remove class

commit 6049c32839
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 19 15:46:42 2024 +0200

    Compute tokens from each activated set

commit 8e02dced2f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 19 10:49:46 2024 +0200

    Extract to function

commit 97436531d0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 19 10:46:48 2024 +0200

    Showing only active sets

commit 8660c372dc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 19 09:41:23 2024 +0200

    Add theme deletion

commit 3413d4b42f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 19 09:09:09 2024 +0200

    Add tests

commit 93a23c66ec
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 19 09:01:08 2024 +0200

    Docstrings

commit e8bbb75008
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 19 08:49:03 2024 +0200

    Implement group theme switching

commit 9a745ea8bc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 19 08:05:19 2024 +0200

    Add active theme toggling

commit f0e0e9334e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 19 07:29:20 2024 +0200

    Cleanup

commit ae1c30ad56
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 14:22:56 2024 +0200

    Allow providing set name

commit e502def755
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 14:21:25 2024 +0200

    Show themes

commit 62712ef8da
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 13:59:18 2024 +0200

    Cleanup styles

commit 6a7ced3204
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 13:36:54 2024 +0200

    Add token set visibility toggle

commit 636c3b822c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 12:22:57 2024 +0200

    Example styling

commit c2a045ad5b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 11:44:41 2024 +0200

    Add selected sets UI

commit 0f95ddef8f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 11:32:36 2024 +0200

    Add new sets to active theme

commit 3e41e7d234
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 11:32:20 2024 +0200

    Fix workspace-data key missing

commit 879ef1123f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 10:32:59 2024 +0200

    Create temporary theme when creating set

commit 9329513949
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 08:04:41 2024 +0200

    Add token set deletion

commit ae39586d8c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 07:10:15 2024 +0200

    Add temporary theme

commit 4c1bc81b19
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 07:10:08 2024 +0200

    Add name

commit 7406af2e79
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 07:09:59 2024 +0200

    Add theme creation

commit 8482a128de
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 07:09:17 2024 +0200

    Fix expeted id instead of set

commit 3695ba3438
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 07:09:07 2024 +0200

    Add token theme data scaffold

commit 35759792a3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 06:24:15 2024 +0200

    Render grouped themes ui

commit f0aaa29d66
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 06:24:03 2024 +0200

    Add type functions

commit cefa498f4d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 16 06:23:53 2024 +0200

    Add group and selected properties to theme

commit f3d4346c0d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 18:52:42 2024 +0200

    Add create token-set event

commit 1f0c1dbbe6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 18:52:31 2024 +0200

    Update shapes on token set switch

commit 587a2936e6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 18:26:37 2024 +0200

    Add simple UI

commit 73078d802a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 18:26:20 2024 +0200

    Add refs

commit eaf568f154
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 14:26:22 2024 +0200

    Get tokens from current or first token set

commit ead8a983ab
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 14:26:12 2024 +0200

    Move to token-set namespace

commit 9dd681c156
Merge: b2962b560 43e064a76
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Aug 15 12:28:19 2024 +0200

    Merge pull request #254 from tokens-studio/fix-token-editing

    Fix token editing

commit 43e064a768
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 10:12:45 2024 +0200

    Update doc string

commit 4bd3b14adb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 10:07:12 2024 +0200

    Add unit to tests

commit e4e488a9ee
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 10:03:25 2024 +0200

    Adds style-dictionary test

commit c6d13af071
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 09:21:49 2024 +0200

    Fix validation not working while editing [*]

    [*] We've passed the resolved tokens to the validation,
    but the validation needs the original tokens set.

commit 6be2ca8491
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 15 09:21:18 2024 +0200

    Fix resolved value not showing up when editing token

commit b2962b5603
Merge: c7d4db900 ecf4fb8bd
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Aug 14 19:41:36 2024 +0200

    Merge pull request #251 from tokens-studio/fix-spacing-token

    Fixes design tab spacing token

commit ecf4fb8bd0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 14 16:52:46 2024 +0200

    Fix popover position

commit 1ba2acea7c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 14 16:39:43 2024 +0200

    Fix crash for applying spacing layout token

commit cf9ef2ae60
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 14 15:33:24 2024 +0200

    Remove unused function

commit 74c6228c25
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Aug 14 17:15:30 2024 +0530

    add dom/stop-propagation

commit 188e7d220a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 14 09:25:17 2024 +0200

    Fix name

commit c7d4db900e
Merge: d8621974c 726b0a267
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Aug 14 09:16:23 2024 +0200

    Merge pull request #245 from tokens-studio/use-token-name-ref

    Use token name ref

commit 1135b7e2db
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 13 18:30:00 2024 +0200

    Update token sets

commit 71439637aa
Merge: 21c42626a d8621974c
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 21:56:06 2024 +0530

    Merge branch 'token-studio-develop' into token-sets-ui

commit 21c42626ae
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 21:51:31 2024 +0530

    remove comment

commit 007cf0fb8a
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 21:50:55 2024 +0530

    remove comments and unused import

commit 46c73fe51f
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 21:44:08 2024 +0530

    formatting

commit 66170eb889
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 21:42:08 2024 +0530

    make current-set-id the key on div element

commit 68c0d93f91
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 21:12:38 2024 +0530

    change sets list div to ul

commit 7addba71fb
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 21:07:52 2024 +0530

    remove debug statements

commit 950257a212
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 20:42:42 2024 +0530

    change eye icon size

commit 9aadb8c72f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 13 16:18:24 2024 +0200

    Add test

commit fa230a4224
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 19:31:34 2024 +0530

    add folder-open icon and use for open groups

commit 2f2ed0a42f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 13 15:45:38 2024 +0200

    Cleanup

commit a4865522cc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 13 15:25:36 2024 +0200

    Select token set on create

commit ba31914ca4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 13 14:41:58 2024 +0200

    Fix typo

commit c275923621
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 13 14:41:49 2024 +0200

    Fix indent

commit ec01ce7550
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 13 14:41:18 2024 +0200

    Ensure vector

commit bcd4b6d9ec
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 13 13:31:43 2024 +0200

    Fix schema errors

commit 547358d579
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 13 11:57:06 2024 +0200

    Add token set changes

commit bcf61f34fe
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 14:11:30 2024 +0530

    add current set and selected set

commit ad9a4e7244
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Aug 13 01:17:18 2024 +0530

    Add full lenght highlight

commit 9ff3a135a8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 12 10:50:47 2024 +0200

    Cleanup

commit 6c3415b92c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 6 14:56:11 2024 +0200

    Differentiate groups and sets

commit dbddd7fb68
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 6 14:26:30 2024 +0200

    Add token themes & sets schema

commit 726b0a2671
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 9 18:04:33 2024 +0200

    Fix :applied-tokens not being updated

commit 51a27c07ec
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 9 18:03:47 2024 +0200

    Use token identifier

commit 9ff4567955
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 9 18:03:20 2024 +0200

    Remove unused function

commit 5552295d61
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Aug 9 17:37:36 2024 +0200

    Add docstring

commit b93b0b209a
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu Aug 8 21:40:35 2024 +0530

    Add hover styles and collapse capabilities

commit bb3a22a219
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu Aug 8 18:46:58 2024 +0530

    add hide/show icon

commit e992bf0aa6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 15:13:04 2024 +0200

    Fix sizing test

commit 8b8b909fb7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 15:12:28 2024 +0200

    Parse values with unit

commit 2d67a92d64
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 11:39:58 2024 +0200

    Fix getter

commit a073520d0e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 11:22:40 2024 +0200

    Restore tests to work with new identifier

commit e27e2d357c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 11:09:12 2024 +0200

    Add simple applying test

commit d98e982664
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 11:07:32 2024 +0200

    Cleanup

commit 31674db11d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 11:07:24 2024 +0200

    Skip parsing on numbers

commit 0684d893e0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 11:06:49 2024 +0200

    Return resolved & parsed token names map

commit 37f23855e8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 09:52:51 2024 +0200

    Fix re-find only accepting string values throw

commit 2e8e33d701
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 09:40:26 2024 +0200

    Add token value parsing function

commit 980238e27b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 8 09:22:32 2024 +0200

    Move find-token-references to token namespace

commit b28a45c2d8
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu Aug 8 00:14:36 2024 +0530

    add more changes working tree display

commit fcea989586
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Aug 7 22:39:41 2024 +0530

    add more changes

commit 1434ddb5d5
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Aug 7 20:58:21 2024 +0530

    change fotn color

commit 252797183c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 7 15:14:32 2024 +0200

    Use :name as the token identifier [*]

    [*] Using uuid as the token identiefier for :applied-tokens is not
    correct as we want to merge all sets together by their name, to get the
    final values.

commit d8621974c2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 7 17:14:05 2024 +0200

    Update with upstream

commit 192f847d50
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 7 17:13:39 2024 +0200

    Ignore rxjs errors

commit c9673ca828
Merge: d7ee804ca 22f3dba84
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 7 16:21:08 2024 +0200

    Merge remote-tracking branch 'penpot/develop' into token-studio-develop

commit d7ee804ca3
Merge: eb9b4be6e edb89bccc
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Aug 7 12:53:02 2024 +0200

    Merge pull request #243 from tokens-studio/fix-tests

    Temporary fix for tests

commit edb89bcccb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Aug 7 12:38:24 2024 +0200

    Temporary fix for tests [*]

    [*] Async tests got broken with the latest upstream.

    This will still print a bunch of warnings from rxjs but the tests are
    still running.

commit eb9b4be6ea
Merge: e02611da2 4ae467987
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Aug 7 08:26:08 2024 +0200

    Merge pull request #241 from tokens-studio/sync-master

    Sync penpot master

commit 02a19a6b33
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Aug 7 00:57:13 2024 +0530

    Next commit

commit 22e497398f
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Aug 7 00:08:12 2024 +0530

    Initial commit

commit 4ae467987a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 6 11:25:31 2024 +0200

    Update changes

commit 3bd0318999
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 6 11:16:38 2024 +0200

    Update lock file

commit dd8780db69
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 6 11:16:30 2024 +0200

    Use register

commit 5fbbdd36fd
Merge: e02611da2 36ac81bb4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Aug 6 11:06:51 2024 +0200

    Merge remote-tracking branch 'penpot/develop' into token-studio-develop

commit e02611da20
Merge: 57c9d6d3a f7e770192
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue Aug 6 10:31:13 2024 +0200

    Merge pull request #238 from tokens-studio/213-opacity-fixes-03

    Fixes Opacity

commit f7e7701923
Merge: 6cb3afe87 57c9d6d3a
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue Aug 6 08:23:39 2024 +0200

    Merge branch 'token-studio-develop' into 213-opacity-fixes-03

commit 57c9d6d3a9
Merge: 3c7261e75 fe9bb69c7
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue Aug 6 06:38:31 2024 +0200

    Merge pull request #239 from tokens-studio/236-stroke-width-fix

    Fix stroke width applying crash

commit fe9bb69c75
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 5 11:45:32 2024 +0200

    Update CHANGELOG

commit c9d1fe44e9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 5 11:43:46 2024 +0200

    Add stroke-width test

commit 2a97749d23
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 5 11:42:36 2024 +0200

    Add shape property passing

commit 3826afb76b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 5 11:18:19 2024 +0200

    Fix applying stroke

commit 6cb3afe87f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 5 11:05:49 2024 +0200

    Add opacity tests

commit 62a9dd6582
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 5 10:54:46 2024 +0200

    Cleanup

commit ad468582b3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 5 10:53:59 2024 +0200

    Add changelog

commit c29024bd62
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Aug 5 10:51:35 2024 +0200

    Dont update values outside of 0..1 (e.g.: 20)

commit 1f88c8288a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 11:08:15 2024 +0200

    Parse double to preserve opacity

commit 3c7261e75b
Merge: ab72bdf09 72c5c3ec9
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Fri Aug 2 08:56:30 2024 +0200

    Merge pull request #231 from tokens-studio/update-token-shapes

    Update token shapes

commit 72c5c3ec9a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 15:45:37 2024 +0200

    Cleanup

commit 13163a4571
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 15:37:53 2024 +0200

    Clean up debugging code

commit 0c757f05e3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 15:37:39 2024 +0200

    Apply actions directly

commit fc6d64fb5d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 15:32:33 2024 +0200

    Fix import

commit 518441e582
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 12:12:03 2024 +0200

    Fix spacing token click will add padding

commit fdce370bb6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 12:05:15 2024 +0200

    Disable debug

commit 9ebd743635
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 11:09:36 2024 +0200

    Testing comment

commit cc6f34f78a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 11:07:02 2024 +0200

    Fix trying to update shapes for deleted tokens crash

commit feb438f882
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 10:41:45 2024 +0200

    Safety net

commit 68b32448d1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 10:41:03 2024 +0200

    Fix exact match of diff adding nil attrs group and crashing the app

commit ac27f95091
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 09:41:28 2024 +0200

    Fix undo deleting the token on update

commit 68415b6668
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 09:14:21 2024 +0200

    Update tokens after shape update

commit e52623c728
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Aug 1 09:13:58 2024 +0200

    Update shapes in one undo step, resolve tokens from state not cache atom

commit a1fefe66ae
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 31 17:26:50 2024 +0200

    Working updates!

commit d22234fe2a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 31 16:51:55 2024 +0200

    Cleanup

commit 0166c38486
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 31 16:43:03 2024 +0200

    Split logical attribute groups

commit 69d9359237
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 31 14:36:09 2024 +0200

    Collecting update functions by attributes

commit 6225f59ea0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 31 14:04:00 2024 +0200

    Cleanup

commit ab72bdf09c
Merge: dde8ab068 1d4b41750
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue Jul 30 08:02:50 2024 +0200

    Merge pull request #224 from tokens-studio/ux-context-menu

    Ux context menu

commit 1d4b417501
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 30 06:57:21 2024 +0200

    Fix missing function shorthand

commit f69db7ce9e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 18:43:47 2024 +0200

    Cleanup

commit 5e33eab7d0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 18:31:11 2024 +0200

    Fix position updating

commit 9340ba9cc0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 18:30:59 2024 +0200

    Allow passing custom on-update-shape function

commit ededd23849
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 17:48:30 2024 +0200

    Trigger Build

commit b423a9c782
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 17:43:32 2024 +0200

    Always update all layout-gap on token pill click

commit 70904dbc64
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 16:38:40 2024 +0200

    Trigger Build

commit 9ba4776c8e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 16:34:26 2024 +0200

    Trigger Build

commit c92decedeb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 16:21:42 2024 +0200

    Trigger Build

commit a893a66ec8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 16:07:33 2024 +0200

    Fix crash on applying col/row gap

commit 3f14af9e03
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 16:00:46 2024 +0200

    Fix highlighting for dimensions token

commit 596d662ca8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 15:24:17 2024 +0200

    Cleanup

commit 1eea55ad43
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 15:09:35 2024 +0200

    Test

commit 55ed79d968
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 14:22:37 2024 +0200

    Move to sidebar, should not be rendered in root

commit 6fc370bb30
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 14:22:07 2024 +0200

    Fix token position wrong, component gets rendered on user mount

commit 1633f8035e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 29 13:51:17 2024 +0200

    Indent

commit 9bec2509c9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 25 10:11:36 2024 +0200

    Better context-menu position, remove hardcoded value

commit 1e481412e8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 25 09:12:23 2024 +0200

    Remove old token applying events

commit cc41a42dfa
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 25 09:11:03 2024 +0200

    Update CHANGELOG

commit a3a4883875
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 25 08:58:26 2024 +0200

    Cleanup

commit f094654837
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 25 08:56:02 2024 +0200

    Fix only shape ids being applied

commit f93a5ab109
Merge: 957ad0dae dde8ab068
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 25 08:42:17 2024 +0200

    Merge remote-tracking branch 'origin/token-studio-develop' into ux-context-menu

commit 957ad0dae3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 16:21:48 2024 +0200

    Always highlight if one of the attributes is active, but only apply minimal set on pill click

commit b9b4abf1e0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 16:10:41 2024 +0200

    Fix edit modal not opening

commit cb942996a9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 16:05:43 2024 +0200

    Fix render-loop after token was deleted

commit 37bef1e2ea
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 16:05:29 2024 +0200

    Cleanup

commit b392c3ba65
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 15:46:14 2024 +0200

    Move token change events to changes ns

commit 56e72b5247
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 15:29:40 2024 +0200

    Refactor - Separate core into namespaces: changes, token_types

commit 03370c267d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 15:02:10 2024 +0200

    Cleanup

commit d5a03e154b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 14:57:33 2024 +0200

    Cleanup

commit 386a4c94ba
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 14:51:59 2024 +0200

    Disallow clicking pill when nothing is selected

commit 5e911d814c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 14:49:39 2024 +0200

    Show attribute actions only when something is selected

commit 310033fd75
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 14:20:08 2024 +0200

    Inline attributes

commit 46250003d3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 14:17:43 2024 +0200

    Reuse all-or-sepearate-actions for border-radius

commit 871402bd84
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 14:07:42 2024 +0200

    Fix overriding of existing radius-4

commit 38499e2f1f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 14:07:29 2024 +0200

    Fix properties

commit 893e533afe
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 14:01:56 2024 +0200

    Cleanup

commit e6889fc92e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 13:41:32 2024 +0200

    Fix typo

commit c11c1e0c03
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 13:41:08 2024 +0200

    Use all-or-sepearate-actions for gap

commit 335808bf03
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 13:41:00 2024 +0200

    Remove unneeded actions

commit cbd5d42069
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 13:36:38 2024 +0200

    Simplify

commit 113fc9891b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 13:29:26 2024 +0200

    Simplify component & css

commit fbd2ab833d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 10:59:26 2024 +0200

    Inline separator

commit 08cc777096
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 10:58:34 2024 +0200

    Restructure

commit 81c83f9dd4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 10:55:22 2024 +0200

    Recurse tree instead of repetition

commit f20313e7f8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 09:43:28 2024 +0200

    Add dimensions sub-menu

commit 1776591fec
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 09:42:09 2024 +0200

    Fix react index warning

commit aa75f30858
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 24 09:19:31 2024 +0200

    Allow type overriding via prop

commit 62f7f8a74f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 23 16:35:07 2024 +0200

    Add sizing

commit 65dbafafb8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 23 16:02:14 2024 +0200

    Add width/height applying

commit 214a323682
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 23 16:01:56 2024 +0200

    Add abstract method for a all or seperate actions

commit da3f2f820c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 23 15:28:13 2024 +0200

    Add generic context menu actions

commit cabc3d3f36
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 23 14:55:14 2024 +0200

    Simplify passed prop date

commit bad9056d54
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 23 11:35:07 2024 +0200

    Update gap

commit 4cf8b2c143
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 23 10:54:23 2024 +0200

    Extract gap as extra function

commit 39822a3b31
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 23 10:49:19 2024 +0200

    Add single padding

commit 0e858d880d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 23 10:37:51 2024 +0200

    Add horizontal/vertical padding toggle

commit dde8ab0680
Merge: 64da0983f cb051d2e5
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Jul 23 13:02:21 2024 +0530

    Merge pull request #223 from tokens-studio/fic-spacing-crash-on-non-layout

    Fix app crashing when spacing padding is applied to a shape without a…

commit 2411eeb644
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 22 18:23:12 2024 +0200

    Add separate gap

commit c00023319a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 22 18:13:37 2024 +0200

    Extract data

commit fd2f5537cf
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 22 18:07:16 2024 +0200

    Extract common logic

commit 2836ff2693
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 22 17:07:42 2024 +0200

    Fix actions

commit f731a30f81
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 22 13:54:36 2024 +0200

    Allow removing other attributes with apply-token function

commit 91033d6dea
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 22 11:30:27 2024 +0200

    Fix indent

commit 64da0983f3
Merge: 2f17b79be 337e1c9fa
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Fri Jul 19 00:30:15 2024 +0530

    Merge pull request #222 from tokens-studio/fix-stroke-width-crash

    Fix application crashing when stroke width is applied to a shape with…

commit cb051d2e5b
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Fri Jul 19 00:28:00 2024 +0530

    Fix app crashing when spacing padding is applied to a shape without a layout

commit 337e1c9fa0
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu Jul 18 23:13:51 2024 +0530

    Fix application crashing when stroke width is applied to a shape without a stroke

commit 359ec592fb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 15:40:33 2024 +0200

    Single attribute context menu

commit ae2da534e9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 15:40:18 2024 +0200

    Move radius updating to core

commit 9bf763efb3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 15:19:48 2024 +0200

    Add all action

commit 77fe4d556f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 15:10:51 2024 +0200

    Convert border-radius to new UX

commit 7b2d11019c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 15:10:01 2024 +0200

    Only show atrribute actions when shapes are selected

commit bf994fcd56
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 14:40:57 2024 +0200

    Rename

commit 3ad009b515
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 14:40:35 2024 +0200

    Fix lint

commit 82b44e6569
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 14:40:07 2024 +0200

    Inline concat

commit da0389e304
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 14:38:19 2024 +0200

    Improved logic to run once for all shapes

commit 90618ec89a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 11:41:25 2024 +0200

    Add separator between default actions and attribute actions

commit 2f17b79bef
Merge: c2777ed6e bc1f27eac
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Mon Jul 8 13:53:10 2024 +0200

    Merge pull request #216 from tokens-studio/ux-improvements

    UX improvements

commit db7391e4cb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 11:40:05 2024 +0200

    Separate entries

commit e75f9a7c7f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 11:06:57 2024 +0200

    Add predicate for all test

commit 62ecee2cf8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 8 10:24:23 2024 +0200

    Add grouping function by type

commit 3c67872d3c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jul 5 14:44:57 2024 +0200

    Add future test cases for providing a toggle all/attributes

commit 5a358e3d0c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jul 5 14:13:14 2024 +0200

    Extract singular token applied predicate

commit bc1f27eac9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jul 5 09:18:36 2024 +0200

    Trigger Build

commit 0fad53ea6c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jul 5 08:55:01 2024 +0200

    Convert stroke to event

commit c7a46c31b4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jul 5 08:53:45 2024 +0200

    Convert layout spacing to function

commit c70bb876b2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jul 5 08:31:38 2024 +0200

    Add changelog

commit 4fc7efd3b7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 16:03:32 2024 +0200

    Restore performance measuring lines

commit 4a329a6318
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 15:52:58 2024 +0200

    Override http server

commit 828e3a719f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 15:29:42 2024 +0200

    Disable running tests from shadow-cljs directly

commit 785961f7c6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 14:31:50 2024 +0200

    Cleanup

commit 55713275b6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 14:14:06 2024 +0200

    Add test for overriding token

commit f20c08f31b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 14:05:20 2024 +0200

    Specify tests

commit 893e790787
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 11:41:00 2024 +0200

    Only remove given token

commit b73cdd15e0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 11:28:15 2024 +0200

    Add helper to remove attributes from applied-tokens

commit 658e7ebd0a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 11:15:06 2024 +0200

    Cleanup

commit 694baeee0c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 11:12:49 2024 +0200

    Add sizing test

commit 7abfaef1cb
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 11:08:46 2024 +0200

    Test applying rotation

commit 322c8ef8ec
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 11:06:48 2024 +0200

    Update opacity

commit b43d16008f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 10:51:08 2024 +0200

    Extract to helpers

commit 1f0f35e754
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 10:48:27 2024 +0200

    Remove unused

commit a842cb2d7d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 10:41:57 2024 +0200

    Cleanup

commit 8f806ef1fe
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 10:41:46 2024 +0200

    Test single property updates

commit f3261c9b0f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 10:41:10 2024 +0200

    Fix emit! side-effect

commit 818aa043ca
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 10:40:59 2024 +0200

    Wrap in undo sequence

commit 596480d177
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 10:05:36 2024 +0200

    Add test to verify toggle removes token for applied & unapplied

commit ab62c5b4ef
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 10:00:58 2024 +0200

    Add helper to apply token to shape

commit 581ced0ab8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 10:00:44 2024 +0200

    Abstract into helper

commit e85de19a5e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 09:29:48 2024 +0200

    Add multiple shapes test

commit 8370fd06d4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 09:29:43 2024 +0200

    Remove cb

commit 3793e98660
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 09:29:16 2024 +0200

    Disable complete log

commit b12e59a8d7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jul 4 09:13:02 2024 +0200

    Rename event to toggle-token

commit 71976ed7e9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 3 18:24:09 2024 +0200

    Add helpers for creating test tokens

commit 0730ecef46
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 3 17:15:23 2024 +0200

    Cleanup

commit 219d184e6c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 3 17:06:08 2024 +0200

    Add multiple tokens for tests

commit a7e735bd81
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 3 17:04:47 2024 +0200

    Add helper for asnc stores

commit ed7aad6c4e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 3 16:11:39 2024 +0200

    Async token event tests working

commit e203646085
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 3 11:16:16 2024 +0200

    Naming

commit 1e70a4d714
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 3 11:09:50 2024 +0200

    Implement using rx observables instead of side-effects

commit 97db3c29ca
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jul 3 09:50:54 2024 +0200

    Trying to convert to rx structure

commit 50635ae879
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 2 16:06:41 2024 +0200

    Found error in handler logic, need rx streams

commit 3e5126251c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 2 15:19:31 2024 +0200

    Add failing logic test

commit 10d92f598c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 2 15:03:09 2024 +0200

    Add nodemon watcher

commit c486ea81f4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 2 15:03:04 2024 +0200

    Cleanup

commit f2358b9827
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jul 2 08:22:27 2024 +0200

    Use toggle function

commit c2777ed6e3
Merge: 5c5b37826 224b656d5
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Mon Jul 1 18:43:17 2024 +0200

    Merge pull request #211 from tokens-studio/fix-sub-name-space

    Fix token naming clashes

commit 5cef23267c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 1 14:14:36 2024 +0200

    Move to tokens ns, add test

commit cf07de3bcf
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 1 14:05:06 2024 +0200

    Add tests for token-applied?

commit e38a943ce0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 1 13:51:20 2024 +0200

    Move token-applied? to token ns

commit 224b656d57
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 1 10:40:38 2024 +0200

    Add CHANGELOG

commit 111be97228
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 1 10:31:16 2024 +0200

    Remove logs

commit ec511cc589
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 1 10:30:03 2024 +0200

    Fix setting token to own path

commit 9d637cbe5e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 1 10:16:52 2024 +0200

    Path selector test predicate is enough

commit 4a85ef3608
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 1 10:16:15 2024 +0200

    Split path/selector for disallowing creating tokens at path segments

commit a98f59469e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jul 1 09:56:45 2024 +0200

    Add - to allowed token-name

commit 174d91a519
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 28 14:39:36 2024 +0200

    Add function to check if a token can be placed under a name path

commit 48a7c52664
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 28 14:17:42 2024 +0200

    Separate errors

commit 2fa152d364
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 28 13:51:32 2024 +0200

    Move to token namespace

commit 504369ec13
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 28 13:43:41 2024 +0200

    Move tokens-name-tree to core, add test

commit ef5f019200
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 28 13:34:54 2024 +0200

    Add helper utility to convert name to path

commit 6da855c741
Merge: 3a500fb8a a4bbef991
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 28 11:24:55 2024 +0200

    Merge branch 'fix-token-reference-issue' into 199-branch-name

commit a4bbef9917
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Fri Jun 28 14:43:49 2024 +0530

    Fix token reference issue when name has .

commit 3a500fb8a7
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 26 19:40:06 2024 +0530

    Update CHANGELOG.md with PR link

commit 00dabaf38c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 26 16:08:21 2024 +0200

    Remove comment form

commit f24c314d63
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 26 16:04:50 2024 +0200

    Update

commit f9530c5a10
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 26 16:01:41 2024 +0200

    Restrict token naming

commit 5c5b378262
Merge: 3a594d239 4aac3eee7
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Fri Jun 28 08:19:57 2024 +0200

    Merge pull request #204 from tokens-studio/fix-deploy

    Fix deploy

commit 4aac3eee7f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 28 08:18:43 2024 +0200

    Test synchronize

commit 325ad66a46
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 28 08:16:26 2024 +0200

    Fix branches not being re-deployed after push

commit 3a594d2393
Merge: bd5a0d2d1 b2a983fd0
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu Jun 27 16:31:14 2024 +0200

    Merge pull request #203 from tokens-studio/fix-new-document-token

    Fix creating a token issue on empty document

commit b2a983fd05
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jun 27 16:07:47 2024 +0200

    Fix creating a token issue on empty document

commit bd5a0d2d1b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 26 15:06:22 2024 +0200

    Cleanup

commit 19c6c6d3bf
Merge: 7fa31b143 c9a40ee9b
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 26 17:58:01 2024 +0530

    Merge pull request #195 from tokens-studio/json-export-changelog

    Add Json export Changelog

commit c9a40ee9b3
Merge: 350654f96 7fa31b143
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 26 17:57:49 2024 +0530

    Merge branch 'token-studio-develop' into json-export-changelog

commit 350654f968
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 26 17:51:23 2024 +0530

    Update CHANGELOG.md image

commit 7fa31b143e
Merge: 357a0781b bf1c9e2c1
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 26 17:48:08 2024 +0530

    Merge pull request #198 from tokens-studio/json-dtcg-format

    Make tokens JSON export DTCG compatible

commit bf1c9e2c18
Merge: 96bfce13b 357a0781b
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 26 17:47:54 2024 +0530

    Merge branch 'token-studio-develop' into json-dtcg-format

commit 357a0781bb
Merge: 5ca916f8c 86fd667a1
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Jun 26 14:11:08 2024 +0200

    Merge pull request #194 from tokens-studio/style-dictionar-validation

    Token Insert/Edit Validation + Value Preview

commit 96bfce13be
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 26 17:28:10 2024 +0530

    Update CHANGELOG.md image

commit d6f1e2efc9
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 26 12:36:01 2024 +0530

    Update CHANGELOG

commit 158d5cba31
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 26 12:32:07 2024 +0530

    Make tokens JSON export DTCG compatible

commit aabbe2fd94
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Jun 25 22:34:09 2024 +0530

    Update CHANGELOG

commit 86fd667a11
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 17:06:52 2024 +0200

    Hide template section in preview document

commit 56976e2499
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 17:04:13 2024 +0200

    Update CHANGELOG

commit 9f6c587c95
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 16:46:15 2024 +0200

    Remove duplicate similar errors

commit 9f3e1743a1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 16:45:01 2024 +0200

    Cleanup

commit e1b683f670
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 16:43:52 2024 +0200

    Cleanup

commit b4d1ef3fc7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 16:40:48 2024 +0200

    Cleanup

commit b924bbc9c7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 16:39:43 2024 +0200

    Cleanup

commit 656cc00923
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 16:38:28 2024 +0200

    Add missing deps

commit b89dc759be
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 16:36:21 2024 +0200

    Cleanup

commit 135ecf0e3a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 16:33:07 2024 +0200

    Cleanup

commit af374276e4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 16:30:57 2024 +0200

    Extract missing reference error check

commit 2c42ca5a4b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 14:24:20 2024 +0200

    Cleanup

commit b905ff7d2c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 14:18:07 2024 +0200

    Validate forms again on submit

commit eb123bf8ef
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 12:15:14 2024 +0200

    Extract token validation

commit 6e9623153c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 11:55:57 2024 +0200

    Remove caching layer for now

commit d0f8e9612a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 11:52:39 2024 +0200

    Validate name before submitting

commit 5df0cf545e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 11:33:18 2024 +0200

    Remove form-touched work-around

commit eac7d9288b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 11:30:53 2024 +0200

    Fix on-submit taking old ref-values when user submits before errors have been validated

commit 05f6cfc4b0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 11:30:45 2024 +0200

    Remove unneeded state

commit 33131fa943
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 11:15:43 2024 +0200

    Restore token saving

commit ca98747dea
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 11:02:21 2024 +0200

    Add description with schema

commit d2bdc6c624
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 25 10:40:31 2024 +0200

    Fix ref logic

commit 5ca916f8c4
Merge: 1ca3f2970 ee057c498
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 24 20:53:31 2024 +0530

    Merge pull request #191 from tokens-studio/tokens-json-export

    Tokens json export

commit ee057c498e
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 24 20:44:08 2024 +0530

    Simplify tranform tokens function

commit e0be30bb79
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 24 15:58:19 2024 +0200

    Dont show error when unfocusing name input field, but keep form disabled

commit 29e3171bd9
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 24 19:07:53 2024 +0530

    Incorporate styling changes to match Penpot design language

commit c98162d0bf
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 24 15:24:22 2024 +0200

    Move callback function to component

commit fb7b11a139
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 24 18:50:36 2024 +0530

    Remove : from token type in export

commit db26b38e81
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 24 18:47:12 2024 +0530

    Modify transform tokens to nest within token names

commit 28f25da9e8
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 24 14:29:29 2024 +0200

    Move to tests

commit 111900c122
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 24 14:23:28 2024 +0200

    Cleanup

commit 10033ead91
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 24 14:23:03 2024 +0200

    Add specific esm testing environment for tokens

commit 2b3f602312
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 24 17:50:24 2024 +0530

    Move json encode functionalities to tokens namespace

commit ba6a6059c1
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 24 14:07:21 2024 +0200

    Move to custom ns

commit 69d9c8e88f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 24 12:44:29 2024 +0200

    Add esm test

commit ab51b43365
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 24 12:44:05 2024 +0200

    Add type

commit 0a73cbc6f1
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 24 14:18:57 2024 +0530

    Move transform and download functionality to core.cljs

commit bbb09567f6
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 24 14:18:35 2024 +0530

    Remove sample json data

commit 5c42514170
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 24 09:59:22 2024 +0200

    Add style dictionary find-token-reference test

commit 75bdda6b07
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Sun Jun 23 00:16:15 2024 +0530

    add some formatting

commit 62fc2cf652
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Sun Jun 23 00:10:02 2024 +0530

    Add initial working export tokens-json

commit 5f25bd8a7b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 19:41:04 2024 +0200

    Add comments

commit 59780a9d4d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 19:40:03 2024 +0200

    Add token finding function

commit 598e4d36fc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 17:19:59 2024 +0200

    Disable on value error

commit 910485008f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 17:19:13 2024 +0200

    Fix name not updating button

commit 39eb964cb7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 17:18:56 2024 +0200

    Reduce debounce timeout

commit dd62c7fe18
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 17:00:56 2024 +0200

    Give new tokens without a name a temporary hardcoded string

commit 1dcdddb2db
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 17:00:45 2024 +0200

    Check for self references

commit 941fb041b6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 17:00:00 2024 +0200

    Add form styling

commit 8db47b5877
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 15:09:46 2024 +0200

    Use initial value

commit 53f01ef46c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 15:04:30 2024 +0200

    Use input as cache key

commit 35ee732701
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 14:59:08 2024 +0200

    Debounced update of resolved value

commit f00ac72fbe
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 10:10:45 2024 +0200

    Revert to use-var

commit e394216f00
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 21 10:02:21 2024 +0200

    Move form out of modal specific code

commit 1ca3f29708
Merge: f000a5145 80ec74f77
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Thu Jun 20 17:03:45 2024 +0200

    Merge pull request #190 from tokens-studio/pr-test

    Test

commit 80ec74f77e
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Jun 20 17:00:38 2024 +0200

    Fix resolver and add an oauth2 proxy

commit ef6074a5af
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Jun 20 15:35:33 2024 +0200

    Test

commit f000a51451
Merge: 15041a8b9 125e14615
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Thu Jun 20 13:29:37 2024 +0200

    Merge pull request #189 from tokens-studio/clean-ci

    Fix proxy cache for config map

commit 125e146150
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Jun 20 13:28:13 2024 +0200

    fix proxy cache for config map

commit 15041a8b9a
Merge: 31344a532 5c93cf9cd
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Thu Jun 20 13:04:29 2024 +0200

    Merge pull request #188 from tokens-studio/clean-ci

    Fix font issues

commit 5c93cf9cd3
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Jun 20 13:03:49 2024 +0200

    Fix font issues
    Fix minio resolution not working
    Fix redis auth on by default

commit 31344a5322
Merge: ea5dbe275 867fd2391
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Thu Jun 20 02:18:31 2024 +0200

    Merge pull request #187 from tokens-studio/clean-ci

    Cleanup

commit 867fd23917
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Jun 20 02:15:35 2024 +0200

    Cleanup

commit ea5dbe275e
Merge: dcf4b7ce6 41bd4c621
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Thu Jun 20 02:06:50 2024 +0200

    Merge pull request #185 from tokens-studio/feat/mailslurper

    Feat/mailslurper

commit 41bd4c621f
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Jun 20 02:06:21 2024 +0200

    Last round of changes

commit 228665f5f2
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Jun 20 00:58:10 2024 +0200

    Pr should be a prefix

commit be6b217ef0
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Jun 20 00:49:33 2024 +0200

    Fix to use the sanitize the backend tag

commit 87b1bc12c2
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu Jun 20 00:40:10 2024 +0200

    Change asset storage

commit 4b61e0d80c
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 21:09:18 2024 +0200

    Fix branch name detection

commit f5514b419a
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 21:02:16 2024 +0200

    Use a raw tag

commit 349bdbb776
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 20:52:33 2024 +0200

    Change to use branch names instead of shas

commit 0fd4f814d8
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 20:47:35 2024 +0200

    Remove node affinity

commit 79b49bae27
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 20:31:21 2024 +0200

    Update namespace

commit dcf4b7ce64
Merge: 596c1997b f45789596
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Wed Jun 19 20:16:39 2024 +0200

    Merge pull request #186 from tokens-studio/feat/clean-images

    Add clean images workflow

commit f457895961
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Wed Jun 19 18:15:53 2024 +0000

    Add clean images workflow

commit b40f222d16
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 20:06:35 2024 +0200

    Add quote

commit 99d6df4588
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 19:58:44 2024 +0200

    Build backend as part of PR

commit 034d5ad5ab
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 19:57:19 2024 +0200

    Overhaul penpot chart

commit 885322d479
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 17:17:00 2024 +0200

    Reestore fields

commit 0830a26be9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 17:11:28 2024 +0200

    Add error state for invalid name

commit 905ccfdec9
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 16:36:00 2024 +0200

    Capitalize chart

commit e3d73be7c5
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 16:35:46 2024 +0200

    Make sure the uppercase goes through

commit 072baf9c7b
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 16:30:45 2024 +0200

    Test PR again

commit 3e20e15ffd
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 16:22:28 2024 +0200

    Try fix PR chart

commit 6ed788aa5a
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 16:15:20 2024 +0200

    Add patch to enable SMTP

commit 0c45d15fe7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 16:01:40 2024 +0200

    Variadic function doesn't work for hooks

commit 596c1997b8
Merge: f3d5b10e1 21ef1586f
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Wed Jun 19 15:57:35 2024 +0200

    Merge pull request #184 from tokens-studio/feat/mailslurper

    Move config from chart to include the smtp settings

commit 21ef1586f0
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 15:56:03 2024 +0200

    Move config

commit f3d5b10e1f
Merge: 2ce3a180e 3e94d4685
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Wed Jun 19 15:37:02 2024 +0200

    Merge pull request #183 from tokens-studio/feat/mailslurper

    Typo in infra manifest

commit 3e94d46850
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 15:35:15 2024 +0200

    Typo

commit 2ce3a180eb
Merge: caa41146c 569db9d1e
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Wed Jun 19 15:27:59 2024 +0200

    Merge pull request #182 from tokens-studio/feat/mailslurper

    Try cleanup namespace control

commit 569db9d1e6
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 15:25:12 2024 +0200

    Try cleanup namespace control

commit caa41146c4
Merge: a2292eb38 5e32a5bbf
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Wed Jun 19 14:56:29 2024 +0200

    Merge pull request #181 from tokens-studio/feat/mailslurper

    Remove onechart for simple manifests

commit 5e32a5bbfd
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 14:53:21 2024 +0200

    Remove onechart for simple manifests

commit a2292eb387
Merge: 4c236ab42 deb7ba982
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Wed Jun 19 14:43:24 2024 +0200

    Merge pull request #180 from tokens-studio/feat/mailslurper

    Setup mailslurper

commit deb7ba9823
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 14:42:04 2024 +0200

    Setup mailslurper

commit 4c236ab423
Merge: 168a5d57d 386bf1bc2
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Wed Jun 19 14:10:43 2024 +0200

    Merge pull request #179 from tokens-studio/fix/persistence

    Add persistence to penpot deploys

commit 386bf1bc2f
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Wed Jun 19 14:09:35 2024 +0200

    Add persistence to penpot deploys

commit 1596dbe155
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 13:54:09 2024 +0200

    Add function to verify already used names

commit deb9cb1120
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 11:26:29 2024 +0200

    Remove debugging code

commit f169d49397
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 11:18:41 2024 +0200

    Remove double cljs conversion

commit 0a73c3aa95
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 11:09:01 2024 +0200

    Validation in modal

commit 168a5d57d4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 10:49:35 2024 +0200

    Add template

commit a4ef2ee8bf
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 10:42:42 2024 +0200

    Add changelog

commit 83515250da
Merge: 0d4e3e862 5a8a32ddc
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed Jun 19 10:10:43 2024 +0200

    Merge pull request #168 from tokens-studio/style-dictionary

    References & Expressions in Tokens

commit 5a8a32ddc7
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 09:43:36 2024 +0200

    Remove items with missing references

commit 23de79bd04
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 19 09:40:26 2024 +0200

    Remove unneeded function

commit 0d4e3e8629
Merge: 35135635c 0105e4206
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 19 12:58:54 2024 +0530

    Merge pull request #174 from tokens-studio/fix-dimensions-keys-applied

    Fix keys applied when dimensions or sizing token is applied directly

commit 35135635c4
Merge: 2ed3ea6d6 0afddac5d
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 19 12:58:43 2024 +0530

    Merge pull request #175 from tokens-studio/fix-min-max-height-error

    Fix/ min and max height-width application

commit 2ed3ea6d6a
Merge: 1ebd2ee3d 3bbee9532
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 19 12:58:25 2024 +0530

    Merge pull request #177 from tokens-studio/remove-registration-questionnaire

    Remove registration questionnaire

commit 3bbee9532f
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 19 12:38:28 2024 +0530

    Fix error message

commit f99239341f
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 19 12:18:39 2024 +0530

    add message to undo this change in the future

commit f405612a25
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 19 12:16:54 2024 +0530

    Remove Onboarding Questionnaire

commit 0afddac5d1
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Jun 18 23:52:54 2024 +0530

    Fix/ min and max height-width application

commit 0105e42068
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Jun 18 23:21:17 2024 +0530

    Fix keys applied when dimensions or sizing token is applied directly

commit b4d7680cb4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 18 11:29:02 2024 +0200

    Show resolved value

commit 742bb6de05
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 18 11:28:09 2024 +0200

    Handle tokens with issues in ui

commit a390942722
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 18 11:19:09 2024 +0200

    Resolve token value

commit cf52e873e2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 18 11:13:26 2024 +0200

    Cleanup

commit 5c2891b247
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 18 11:10:51 2024 +0200

    Use resolved tokens from style-dictionary

commit 9261c53aff
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 18 10:23:52 2024 +0200

    Don't override original value, add resolved value, add missing reference error

commit d65d880845
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 18 09:59:36 2024 +0200

    Silence errors

commit 09609c18ef
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 17 17:07:02 2024 +0200

    Remove compile style dictionary

commit f0bc262a18
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 17 17:05:51 2024 +0200

    Working version

commit 5a64947b08
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 17 16:13:34 2024 +0200

    Add patched StyleDictionary

commit 0a86e3a651
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri Jun 14 10:52:30 2024 +0200

    Simplify

commit c9df90577f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Jun 13 09:27:53 2024 +0200

    Add compiled library

commit 965da83c97
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 12 17:14:34 2024 +0200

    Add workspace-tokens helper

commit 9bc48a3a1a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 12 17:14:27 2024 +0200

    Allow passing custom cache atom

commit 908cc2240f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 12 16:48:13 2024 +0200

    Docs

commit a79d1013bf
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 12 16:45:24 2024 +0200

    Prevent reprocessing the style-dictionary cache multiple times

commit 73e8b80521
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 12 16:19:39 2024 +0200

    Cleanup

commit 2f45ab1b62
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 12 16:19:03 2024 +0200

    Add hook for using resolved tokens cache

commit 0921f8043b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed Jun 12 16:10:02 2024 +0200

    Allow passing of tokens

commit b1b6b5292c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 11 17:52:29 2024 +0200

    Disable invalid token style for now

commit 4fec7d5af2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 11 17:52:12 2024 +0200

    Applying resolved token value

commit 66b4b892df
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 11 16:43:54 2024 +0200

    Fix data-keys being converted to camel-case

commit 4b90e90974
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 11 16:41:50 2024 +0200

    Backporting resolved tokens to the original structure

commit 1519f8f560
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 11 15:12:30 2024 +0200

    Move to ns

commit e691628648
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 11 10:42:25 2024 +0200

    Test out tokens-studio data

commit efd4c5dcca
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue Jun 11 10:24:12 2024 +0200

    Add performance measuring

commit a5b22d5427
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 10 15:50:48 2024 +0200

    Got resolve working

commit 7da772d6a2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 10 11:54:34 2024 +0200

    Add sd function

commit 1023ba866a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 10 10:52:03 2024 +0200

    Add StyleDictionary as compiled lib

commit 1ebd2ee3d7
Merge: dc36f4f6d 8d444b4b0
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Fri Jun 14 12:40:44 2024 +0530

    Merge pull request #172 from tokens-studio/hide-unfunctional-token-sections

    Hide non functional token sections

commit 8d444b4b02
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu Jun 13 21:33:38 2024 +0530

    Hide non functional token types from UI

commit dc36f4f6d3
Merge: 93c249c77 f10a4f28e
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu Jun 13 12:59:49 2024 +0530

    Merge pull request #164 from tokens-studio/other-token-types-context-menu

    Add context menu for opacity, rotation and stroke width tokens

commit f10a4f28ea
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 12 16:18:51 2024 +0530

    Add context menu for opacity, rotation and stroke width

commit 93c249c77a
Merge: 01d2a25c8 3f55536fc
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 12 15:29:30 2024 +0530

    Merge pull request #161 from tokens-studio/dimensions-context-menu

    Dimensions context menu

commit 3f55536fc0
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 10 23:25:11 2024 +0530

    Add custom context menu and fix styling issues with subcontext menu

commit 842b76f3c1
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Fri Jun 7 01:37:26 2024 +0530

    replace 30px with variables

commit e86038d52f
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Fri Jun 7 01:27:18 2024 +0530

    Add CSS to deal with margin before the Sub Context Menu titles

commit 91eb59696c
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu Jun 6 23:09:22 2024 +0530

    Remove children attribute and use submenu instead

commit 67a34c91d8
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 5 23:19:43 2024 +0530

    Add leading spaces to subcontext menu titles

commit 307f472528
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 5 22:23:27 2024 +0530

    remove print statement

commit a5c235754c
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 5 22:06:59 2024 +0530

    Cleanup debug statements

commit a98d6b4c07
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 5 22:06:31 2024 +0530

    Add context menu functionalities for dimensions token

commit ed0d9e1cf5
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 5 13:49:18 2024 +0530

    initial dimensions context menu

commit 819c50eaf8
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed Jun 5 13:49:00 2024 +0530

    change dimension to dimensions across

commit 01d2a25c8c
Merge: e8b755c75 ea593221b
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Jun 4 17:02:04 2024 +0530

    Merge pull request #160 from tokens-studio/sizing-token-context-menu

    Add new changes from token-studio-develop merge

commit ea593221b3
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Jun 4 15:52:52 2024 +0530

    Add new changes from token-studio-develop merge

commit e8b755c757
Merge: 202b72dcd 88d3fc234
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Jun 4 15:47:58 2024 +0530

    Merge pull request #159 from tokens-studio/sizing-token-context-menu

    Add context menu functionalities on sizing tokens

commit 88d3fc234d
Merge: a553253d2 202b72dcd
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue Jun 4 15:46:02 2024 +0530

    Resolve merge conflicts in context_menu.cljs

commit 202b72dcd0
Merge: 1056c6b44 057934c88
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Tue Jun 4 11:23:49 2024 +0200

    Merge pull request #132 from tokens-studio/feat/branch-deploys

    Prefer wait over deploy for build

commit 057934c883
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Tue Jun 4 11:11:58 2024 +0200

    Cleanup PR

commit 3b3fbc2ccd
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Tue Jun 4 11:06:00 2024 +0200

    fix deploys

commit 1056c6b448
Merge: dc14933f3 580076355
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue Jun 4 10:39:03 2024 +0200

    Merge pull request #158 from tokens-studio/142-when-a-token-is-applied-on-a-shape-in-the-context-menu-there-should-be-check-box-indicating-which-attribute-is-applied

    Show checkmark next to selected token attributes

commit a553253d28
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 3 23:34:51 2024 +0530

    remove println statement

commit 193ad115a2
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon Jun 3 23:25:59 2024 +0530

    Add context menu functionalities on sizing tokens

commit 580076355b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 3 15:21:08 2024 +0200

    Show checkmark for applied tokens

commit 65942ef63b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 3 13:39:26 2024 +0200

    Use set of attributes for action generation

commit c1096e15da
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 3 13:39:16 2024 +0200

    Cleanup

commit dc14933f3a
Merge: e89f03393 3c3ef57da
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon Jun 3 10:51:04 2024 +0200

    Merge remote-tracking branch 'penpot/develop' into token-studio-develop

commit e89f03393b
Merge: 5c7e235c9 86e6421b6
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Mon Jun 3 10:48:49 2024 +0200

    Merge pull request #157 from tokens-studio/florian/input-select

    Allow token selection with keyboard from right side

commit 86e6421b68
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 31 16:25:30 2024 +0200

    Disable selection when entering with mouse

commit 710fa0d817
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 31 16:22:01 2024 +0200

    Allow arrow selection

commit 5c7e235c97
Merge: d624a559a c3cee77ef
Author: Akshay Gupta <akshay@hyma.io>
Date:   Fri May 31 18:31:37 2024 +0530

    Merge pull request #155 from tokens-studio/spacing-context-menu

    Spacing context menu

commit c3cee77efb
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Fri May 31 18:19:42 2024 +0530

    remove unused imports and refactor functions

commit d624a559aa
Merge: 420b8cf52 d16f1c773
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Fri May 31 10:46:51 2024 +0200

    Merge pull request #150 from tokens-studio/flex-row-gap-commit

    Spacing tokens

commit 76347228fe
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu May 30 22:25:21 2024 +0530

    Add all spacing token context menu functionalities

commit 84d96a1004
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 29 18:47:17 2024 +0530

    Add initial spacing context menu entries

commit d16f1c773e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 14:53:40 2024 +0200

    Change both properties

commit 7376cb634a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 14:32:09 2024 +0200

    Add padding x/y tokens

commit 0e7e37afc2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 14:21:33 2024 +0200

    Add padding editable select

commit 28bdf62454
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 13:50:31 2024 +0200

    Integrate changes

commit 420b8cf524
Merge: bdefc97c2 c2c0fbf40
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed May 29 13:20:44 2024 +0200

    Merge pull request #146 from tokens-studio/135-flex-row--gap-token-updating-from-the-right-sidebar

    135 flex row  gap token updating from the right sidebar

commit 78f3d54dee
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 10:55:40 2024 +0200

    Add commit

commit c2c0fbf40a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 09:37:24 2024 +0200

    Add spacing/row options

commit 1ad998de23
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 09:28:38 2024 +0200

    Use editable-select for col-gap/row-gap

commit fb5f7e870a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 09:23:47 2024 +0200

    Fix drop-down button spacing

commit 5c83247256
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 09:20:14 2024 +0200

    Prevent selection on disabled selects

commit c6f5da8873
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 09:16:55 2024 +0200

    Move select styles to select component

commit 9a7c944763
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 09:04:49 2024 +0200

    Remove unused classname

commit 985d8d33ff
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 09:02:26 2024 +0200

    Add event to passed arguments [*]

    [*] Needed for layout_container component

commit 384da8555d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 29 08:50:50 2024 +0200

    Dynamically pass props to input

commit bdefc97c21
Merge: 144b164fa bb3ee2278
Author: Akshay Gupta <akshay@hyma.io>
Date:   Tue May 28 17:36:59 2024 +0530

    Merge pull request #140 from tokens-studio/general-token-context-menu-functions

    General token context menu functions and specific context menu functions for border radius

commit bb3ee22780
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue May 28 17:03:26 2024 +0530

    pass context menu attributes as map and some minor fixes

commit e02777b855
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Tue May 28 10:23:20 2024 +0200

    Be explicit in tagging for prs

commit 144b164fa0
Merge: 169d71b2d 96a7cf2e9
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue May 28 10:06:12 2024 +0200

    Merge pull request #139 from tokens-studio/fix-staging

    Fix staging

commit eeb87e49a2
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Tue May 28 09:58:15 2024 +0200

    Cleanup github token usage

commit 9066ad9e39
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue May 28 02:22:25 2024 +0530

    Add border radius specific context menu functions

commit 464bdf3d9c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon May 27 15:09:36 2024 +0200

    Use single undo operation for width/height change

commit 96a7cf2e98
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon May 27 14:50:55 2024 +0200

    Convert kebab keys into camelCase

commit 47d75e7e2a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon May 27 14:43:28 2024 +0200

    Remove closed for now

commit 6ed5dc138d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon May 27 14:43:11 2024 +0200

    Fix editing/saving

commit 169d71b2df
Merge: 65563e2d3 6bacd1d66
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Mon May 27 11:22:27 2024 +0200

    Merge pull request #138 from tokens-studio/124-disable-1password-completion

    124 disable 1password completion

commit 6bacd1d663
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon May 27 11:13:05 2024 +0200

    Disable password manager completion

commit 86d7979e1e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon May 27 11:12:36 2024 +0200

    Remove unused component

commit d1fc43d8d6
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 27 10:38:35 2024 +0200

    Try force deploy branch PR

commit 370a5d9bb8
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon May 27 13:02:24 2024 +0530

    Add initial context menu token specific functionality

commit 65563e2d3c
Merge: 968c6437f 7a8722de1
Author: Akshay Gupta <akshay@hyma.io>
Date:   Fri May 24 18:13:00 2024 +0530

    Merge pull request #133 from tokens-studio/editing-tokens

    :feat editing tokens

commit 968c6437fb
Merge: 75b935187 cbad5033c
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Fri May 24 11:46:45 2024 +0200

    Merge pull request #134 from tokens-studio/123-other-fields-to-update

    Width/Height Token Changing from the sidebar

commit cbad5033c2
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 24 11:25:30 2024 +0200

    Cleanup

commit f52e2e3a41
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 24 10:34:20 2024 +0200

    Differentiate width/height sizing selected properties

commit 49d9b52b12
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 24 10:01:13 2024 +0200

    Cleanup

commit ea9d850412
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 24 10:00:43 2024 +0200

    Fix selectionStart not being detectable (selectionStart doesnt work for number)

commit b6061cc4a0
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 24 10:00:26 2024 +0200

    Fix instant value change applies shape attributes

commit bc620ba2cd
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 24 08:55:04 2024 +0200

    Update width value

commit 595831118d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 24 08:36:28 2024 +0200

    Allow aligning dropwdown to the left

commit 406e8d110c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 24 07:34:43 2024 +0200

    De-Applying token

commit 7a8722de1b
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Fri May 24 00:14:17 2024 +0530

    Add ability to edit existing token attributes

commit 5131b79060
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu May 23 16:22:31 2024 +0200

    Prefer wait over deploy for build

commit 75b9351871
Merge: 557195cd5 84ad8a6be
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Thu May 23 16:19:31 2024 +0200

    Merge pull request #131 from tokens-studio/feat/branch-deploys

    Test PR deploys

commit 84ad8a6be6
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu May 23 15:39:21 2024 +0200

    Escape interpolation

commit f9e1a65631
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu May 23 15:23:27 2024 +0200

    Trigger cleanup as well

commit 66f67ddff4
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Thu May 23 15:13:43 2024 +0200

    Test PR deploys

commit 2dd994799c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 23 09:41:16 2024 +0200

    Abstract API

commit e181065bda
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 23 09:29:17 2024 +0200

    Formatting

commit 1ed692230b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 23 09:24:12 2024 +0200

    Abstract functionality

commit 557195cd55
Merge: 2818d097a 80ff7f769
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu May 23 11:05:12 2024 +0200

    Merge pull request #130 from tokens-studio/129-bug-file-is-crashing-post-applying-a-border-radius-token-to-a-shape

    Fix non-optional keys breaking staging server

commit 80ff7f769c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 23 10:53:18 2024 +0200

    Fix non-optional keys breaking staging server

commit 273a9530ea
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu May 23 13:14:28 2024 +0530

    initial edit commit

commit 2818d097ab
Merge: 1a144192a cc0e4af4b
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu May 23 08:43:51 2024 +0200

    Merge pull request #128 from tokens-studio/119-higlight-applied-token-in-the-editing-field

    Show token value inside shapes panel (border-radius)

commit cc0e4af4bc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 16:37:19 2024 +0200

    Fix token value not being removed after submit

commit b1379ed7de
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 16:35:44 2024 +0200

    Fix refocus prop not being removed

commit 5bccfa9e2f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 16:29:18 2024 +0200

    Dont submit token when text is selected

commit 5806ae7426
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 16:20:40 2024 +0200

    Abstract functions

commit 2eb5efb274
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 16:13:58 2024 +0200

    Cleanup

commit 850bf80ffc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 15:59:22 2024 +0200

    Replace token with value when inserted after token input

commit 6f5930bf15
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 15:43:40 2024 +0200

    Clear token value on blur

commit 2efd6e1584
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 15:36:26 2024 +0200

    Refocus input on token deletion

commit 86b493522c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 15:12:56 2024 +0200

    Remove unneeded focus hack

commit 1a144192a9
Merge: cbfcc5056 04c43acf3
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed May 22 15:00:05 2024 +0200

    Merge pull request #127 from tokens-studio/fix-sass-pipe-break

    Dont break pipe when sass has an error

commit 70336ea45e
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 14:26:37 2024 +0200

    Style focused pill

commit 7e79cf274d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 14:17:56 2024 +0200

    Fix input background being clipped on hover

commit 42df426375
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 14:13:33 2024 +0200

    Style pill and input combination

commit 7c80f87f30
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 14:13:23 2024 +0200

    Show value instead of label, add title

commit 019759392c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 10:23:57 2024 +0200

    Unlink token when pressing backspace on empty input field

commit 7da382dfed
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue May 21 15:47:18 2024 +0200

    Clear value when pressing backspace as last action

commit 35f384ce9b
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue May 21 15:40:34 2024 +0200

    Use custom input value logic when token is applied

commit 50354ccb71
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue May 21 15:40:19 2024 +0200

    Fix state being reset at start

commit 975f41bc08
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue May 21 15:21:01 2024 +0200

    Display regular input field when token is applied [*]

    [*] Numeric input renders default 0

commit 04c43acf39
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 13:48:13 2024 +0200

    Dont break pipe when sass has an error

commit cbfcc50563
Merge: 44f55308a eb168a6f9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 22 13:46:26 2024 +0200

    Merge remote-tracking branch 'penpot/develop' into token-studio-develop

commit 44f55308a6
Merge: e874ed5b6 2b1066535
Author: Akshay Gupta <akshay@hyma.io>
Date:   Wed May 22 15:14:54 2024 +0530

    Merge pull request #126 from tokens-studio/rotation-token

    Add ability to apply rotation token

commit 2b10665356
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 22 15:11:01 2024 +0530

    close applied tokens map schema

commit 13a8872dbd
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 22 15:08:05 2024 +0530

    add rotation to applied tokens schema

commit 3793f1791a
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 22 13:08:59 2024 +0530

    Add ability to apply rotation token

commit e874ed5b6c
Merge: cb7d4409e eca133426
Author: Akshay Gupta <akshay@hyma.io>
Date:   Tue May 21 17:11:21 2024 +0530

    Merge pull request #125 from tokens-studio/remember-token-section-state

    Remember token section open/close state

commit eca1334266
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue May 21 16:52:47 2024 +0530

    Remember token section open/close state

commit cb7d4409e2
Merge: a1f09d69b 9b13444c4
Author: Akshay Gupta <akshay@hyma.io>
Date:   Tue May 21 13:28:34 2024 +0530

    Merge pull request #116 from tokens-studio/spacing-token-layout-update

    spacing token to update only row or column gap as per flex direction

commit a1f09d69b0
Merge: 162e7b6c5 344a27602
Author: Akshay Gupta <akshay@hyma.io>
Date:   Tue May 21 13:27:42 2024 +0530

    Merge pull request #117 from tokens-studio/sort-tokens-by-insert-order

    sort tokens by insert order

commit 344a27602b
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon May 20 22:25:46 2024 +0530

    sort tokens by insert order

commit 9b13444c44
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Mon May 20 21:59:28 2024 +0530

    spacing token to update only row or column gap as per flex direction

commit 162e7b6c58
Merge: 90ab485e7 5954a8698
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 20 12:59:50 2024 +0200

    Merge branch 'token-studio-develop' of github.com:tokens-studio/tokens-studio-for-penpot into feat/port-tracking-and-smoke

commit 90ab485e78
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 20 12:56:43 2024 +0200

    Needs depend on smoke

commit 5954a8698b
Merge: ec36e06b7 851054c61
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Mon May 20 12:45:42 2024 +0200

    Merge pull request #114 from tokens-studio/feat/port-tracking-and-smoke

    Add port label tracking and add a smoke test

commit 851054c617
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 20 12:11:29 2024 +0200

    Add port label tracking and add a smoke test

commit ec36e06b7b
Merge: 0bd3b0598 3caa9d780
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Fri May 17 14:59:28 2024 +0200

    Merge pull request #113 from tokens-studio/108-custom-editable-select-for-token-completion

    Custom editable select for token completion

commit 3caa9d780a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 11:37:36 2024 +0200

    Show checkmark icon for applied tokens

commit ad26d9e2d3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 10:55:24 2024 +0200

    More styling

commit 85a40d19ed
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 10:26:32 2024 +0200

    Extract component

commit b61a59d375
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 10:16:01 2024 +0200

    Extract key down handler

commit ced325e009
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 10:15:22 2024 +0200

    Return selected item map instead of value [*]

    [*] Multiple tokens could have the same value

commit e69bfb8c54
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 09:05:18 2024 +0200

    Style select

commit 8dd2ba7d78
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 09:04:50 2024 +0200

    Fix naming

commit cb980ace44
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 09:04:35 2024 +0200

    Use regular map for options

commit 165e222117
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 08:17:51 2024 +0200

    Only show dropdown when options contain items

commit b0dcbae3ac
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 08:13:55 2024 +0200

    Fix border clipping

commit 6a8887d9cc
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 08:04:23 2024 +0200

    Remove text transform

commit d2107e7f69
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 08:02:06 2024 +0200

    Fix width of drop down

commit 91271b9e41
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 17 07:57:55 2024 +0200

    Custom editable-select

commit 0bd3b0598b
Merge: 23ee54b4b a3d4d6226
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 16 18:43:05 2024 +0200

    Merge remote-tracking branch 'penpot/develop' into token-studio-develop

commit 23ee54b4b7
Merge: bde2b4b3a c654766f8
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Thu May 16 18:37:46 2024 +0200

    Merge pull request #111 from tokens-studio/71-apply-token-from-the-shapes-panel-right-side

    Apply border radius token from the shapes panel

commit bde2b4b3a5
Merge: 3e7a42213 c44ac862f
Author: Akshay Gupta <akshay@hyma.io>
Date:   Thu May 16 17:15:59 2024 +0530

    Merge pull request #110 from tokens-studio/duplicate-token

    add functionality to duplicate token from context menu

commit c44ac862f0
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu May 16 15:48:39 2024 +0530

    simplify duplicate token function

commit c654766f87
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 16 11:43:37 2024 +0200

    Cleanup outdated props

commit 5205b684e9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 16 11:36:08 2024 +0200

    Fix token not being applied

commit e1ae3d55af
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu May 16 14:08:11 2024 +0530

    ad functionality to duplicate token from context menu

commit 23bee8415a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 16 09:59:55 2024 +0200

    Fix missing dependency

commit 48c85d7200
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 16 09:55:57 2024 +0200

    Simplify token application

commit 0d154679e9
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 16 09:44:11 2024 +0200

    Add docstrings

commit c60c5ac34f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 16 09:33:20 2024 +0200

    Apply tokens directly to shape

commit cdca00a986
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu May 16 09:02:48 2024 +0200

    Extract token apply function

commit 4e3af1407d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 15 18:28:04 2024 +0200

    Fix styling of dropdown items?

commit 9a58188dc3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 15 18:20:47 2024 +0200

    Show border-radius tokens as options

commit d9dbaad281
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 15 18:20:28 2024 +0200

    Add tokens map generators

commit 5e301605ad
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 15 17:44:06 2024 +0200

    Extract token grouping to core

commit 622843f18d
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 15 17:43:49 2024 +0200

    Take tokens as ref

commit 8f852bf48f
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 15 17:26:10 2024 +0200

    Use :as

commit 3e7a422136
Merge: f8972efea 591e33340
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed May 15 17:14:41 2024 +0200

    Merge pull request #104 from tokens-studio/fix-sizing-dimensions-mixup

    Fix sizing/dimensions token mixup

commit 591e333400
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Wed May 15 15:40:07 2024 +0200

    Fix sizing/dimensions token mixup

commit f8972efea0
Merge: d4dd49bdb d69cca2d9
Author: Akshay Gupta <akshay@hyma.io>
Date:   Wed May 15 18:56:42 2024 +0530

    Merge pull request #103 from tokens-studio/simple-context-menu

    fix delimiter mismatch and add missing data/tokens package

commit d69cca2d9c
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 15 18:50:30 2024 +0530

    fix delimiter mismatch and add missing data/tokens package

commit d4dd49bdb7
Merge: 157bb01e8 ec5a11731
Author: Akshay Gupta <akshay@hyma.io>
Date:   Wed May 15 18:31:13 2024 +0530

    Merge pull request #97 from tokens-studio/simple-context-menu

    Simple context menu

commit ec5a117318
Merge: d3d454a43 157bb01e8
Author: Akshay Gupta <akshay@hyma.io>
Date:   Wed May 15 18:30:53 2024 +0530

    Merge branch 'token-studio-develop' into simple-context-menu

commit d3d454a43c
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 15 14:50:24 2024 +0530

    move delete token to tokens actions section

commit 5fa2048b23
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 15 14:40:46 2024 +0530

    re-use workspace context menu entry and fix double nested ul

commit 316db61c8a
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 15 13:23:47 2024 +0530

    remove warning modal when deletion of a token

commit fcd7a35b46
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 15 12:59:18 2024 +0530

    move context menu functions to data/tokens

commit 157bb01e8f
Merge: b9e9f9fb1 584ac6341
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Tue May 14 16:39:16 2024 +0200

    Merge pull request #99 from tokens-studio/fix/containerization

    Downtune replica amount. Cleanup redis host

commit 584ac6341d
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Tue May 14 16:37:16 2024 +0200

    Downtune replica amount. Cleanup redis host

commit b9e9f9fb13
Merge: d67311b12 4d14d78ee
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue May 14 16:27:19 2024 +0200

    Merge pull request #98 from tokens-studio/icons-spacing

    Add more space between icon and label, fix icon offset

commit 4d14d78eed
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue May 14 16:01:11 2024 +0200

    Add more space between icon and label, fix icon offset

commit d67311b126
Merge: 230b271be e6f86cda6
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Tue May 14 15:26:01 2024 +0200

    Merge pull request #96 from tokens-studio/95-placeholder-icons

    Add token placeholder icons

commit 8cb9d9c352
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue May 14 18:48:48 2024 +0530

    Add delete token functionality in context menu

commit 31b487ed86
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue May 14 18:25:08 2024 +0530

    remoev translation function

commit 24f1693684
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Tue May 14 18:10:13 2024 +0530

    Add Context Menu for tokens and simple placeholder functions

commit e6f86cda64
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue May 14 14:24:36 2024 +0200

    Add token placeholder icons

commit 230b271be3
Merge: 740024061 677b28218
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue May 14 12:00:45 2024 +0200

    Merge remote-tracking branch 'penpot/develop' into token-studio-develop

commit 7400240616
Merge: 550045cb3 aa8b1f4c7
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Mon May 13 16:42:34 2024 +0200

    Merge pull request #94 from tokens-studio/fix/containerization

    Chart does auto inject the release name

commit aa8b1f4c73
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 13 16:41:51 2024 +0200

    Chart does auto inject the release name

commit 550045cb3b
Merge: 50f69936a 60207fd01
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Mon May 13 16:21:37 2024 +0200

    Merge pull request #93 from tokens-studio/fix/containerization

    Circumvent bug

commit 60207fd01e
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 13 16:21:01 2024 +0200

    Circumvent bug

commit 50f69936a4
Merge: d90755531 f9d4b9f69
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Mon May 13 16:10:32 2024 +0200

    Merge pull request #92 from tokens-studio/fix/containerization

    Add missing secretName

commit f9d4b9f699
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 13 16:09:56 2024 +0200

    Add missing secretName

commit d907555314
Merge: d3c0abc11 e50a46409
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Mon May 13 15:32:21 2024 +0200

    Merge pull request #90 from tokens-studio/fix/containerization

    Add redis. Ingress should be under front end for some reason

commit e50a46409f
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 13 15:31:03 2024 +0200

    Add redis. Ingress should be under front end for some reason

commit d3c0abc11a
Merge: 64dc685f2 98d7895e2
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Mon May 13 15:09:48 2024 +0200

    Merge pull request #85 from tokens-studio/84-border-width

    Stroke Width

commit 64dc685f2a
Merge: 071df4074 79ce39612
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Mon May 13 15:07:23 2024 +0200

    Merge pull request #89 from tokens-studio/fix/containerization

    Fix pull secrets needed to be a reference

commit 79ce396122
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 13 15:06:22 2024 +0200

    Fix pull secrets needed to be a reference

commit 071df4074f
Merge: 309abec88 0ce5c165d
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Mon May 13 14:43:15 2024 +0200

    Merge pull request #88 from tokens-studio/fix/containerization

    Update secrets

commit 0ce5c165db
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 13 14:41:58 2024 +0200

    Update secrets

commit 309abec88a
Merge: 425155153 10aaa966f
Author: SorsOps <80043879+SorsOps@users.noreply.github.com>
Date:   Mon May 13 14:26:44 2024 +0200

    Merge pull request #87 from tokens-studio/fix/containerization

    Change deploy to use alternate chart as truecharts using a weird helm…

commit 10aaa966f9
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Mon May 13 14:25:07 2024 +0200

    Change deploy to use alternate chart as truecharts using a weird helm dependency

commit 98d7895e2a
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Mon May 13 11:23:30 2024 +0200

    Add stroke-width token

commit 4251551535
Merge: eafd4f01e ae263363e
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Fri May 10 17:36:50 2024 +0200

    Merge pull request #83 from tokens-studio/82-opacity

    Add opacity

commit eafd4f01eb
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Fri May 10 14:34:05 2024 +0200

    Use raw manifests

commit 153ea95a55
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Fri May 10 14:02:34 2024 +0200

    Typo

commit 16c893fa60
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Fri May 10 14:01:08 2024 +0200

    Add matrix for docker build

commit 0e94c9851a
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Fri May 10 13:59:09 2024 +0200

    Move workflow file

commit 07583b5e34
Author: SorsOps <80043879+sorsOps@users.noreply.github.com>
Date:   Fri May 10 13:57:17 2024 +0200

    Add deployment config

commit ae263363ed
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu May 9 21:36:38 2024 +0530

    Add opacity

commit 4e3ee7bdab
Merge: 5efcb0f42 42b25479b
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Fri May 10 12:05:06 2024 +0200

    Merge pull request #81 from tokens-studio/value-resolve

    Value resolve

commit 42b25479b3
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 10 10:36:56 2024 +0200

    Highlight invalid token values

commit 5813acea02
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 10 10:26:22 2024 +0200

    Log whole token

commit df48295903
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 10 10:22:09 2024 +0200

    Add resolving function and move to core ns

commit 5efcb0f424
Merge: 2ed4ece23 6d5beb758
Author: Akshay Gupta <akshay@hyma.io>
Date:   Fri May 10 12:25:23 2024 +0530

    Merge pull request #78 from tokens-studio/fix-assets-panel-view

    Fix assets panel tab view

commit 2ed4ece23d
Merge: d81b1f328 9a243e3b4
Author: Akshay Gupta <akshay@hyma.io>
Date:   Fri May 10 12:22:03 2024 +0530

    Merge pull request #76 from tokens-studio/token-pills-wrap

    Add flex wrap to token pills wrapper

commit d81b1f328d
Merge: 68a201374 0c856702c
Author: Akshay Gupta <akshay@hyma.io>
Date:   Fri May 10 12:21:38 2024 +0530

    Merge pull request #80 from tokens-studio/add-spacing-function

    Add simple token spacing application

commit 0c856702c6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Fri May 10 08:36:40 2024 +0200

    Remove unneeded import

commit 76a38bcb0c
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu May 9 21:36:38 2024 +0530

    Add simple token spacing application

commit 6d5beb7583
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu May 9 18:42:33 2024 +0530

    Fix assets panel tab view

commit 9a243e3b4f
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Thu May 9 17:51:48 2024 +0530

    Add flex wrap to token pills wrapper

commit 68a201374c
Merge: 11d4496e9 69ed15e78
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed May 8 14:29:15 2024 +0200

    Merge pull request #74 from tokens-studio/70-sort-sections-by-tokens

    Sort token groups

commit 11d4496e9a
Merge: 6fa1d6eec fd3922936
Author: Florian Schrödl <contact@florianschroedl.com>
Date:   Wed May 8 14:29:02 2024 +0200

    Merge pull request #68 from tokens-studio/65-dimensions

    Dimensions Token

commit 6fa1d6eecc
Merge: 6bb4eec80 3d13015e3
Author: Akshay Gupta <akshay@hyma.io>
Date:   Wed May 8 17:52:33 2024 +0530

    Merge pull request #66 from tokens-studio/close-token-modal

    add ability to close modal once save token button is clicked

commit 69ed15e789
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Apr 25 19:00:00 2024 +0200

    Remove search bar

commit e5a7f87d1c
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Apr 25 19:00:00 2024 +0200

    Sort token groups

commit fd39229367
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Apr 25 19:00:00 2024 +0200

    Add shape dimensions updating

commit a9aac4c867
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Apr 25 19:00:00 2024 +0200

    Move emit to the shape update function [*]

    [*] A shape update might need multiple emit functions

commit 3d13015e30
Author: Akshay Gupta <gravity.akshay@gmail.com>
Date:   Wed May 8 15:16:11 2024 +0530

    add ability to close modal once save token button is clicked

commit 28e6db9bb4
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Apr 25 19:00:00 2024 +0200

    Reuse attribute keys from token schema

commit 6bb4eec805
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Apr 25 19:00:00 2024 +0200

    Remove unneeded on-apply prop

commit 76f42a0aec
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Apr 25 19:00:00 2024 +0200

    Cleanup on-apply-token function

commit f71ce60b11
Merge: e5c564041 e7b065ac6
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Tue May 7 14:39:33 2024 +0200

    Merge remote-tracking branch 'penpot/develop' into token-studio-develop

commit e5c5640413
Author: Florian Schroedl <flo.schroedl@gmail.com>
Date:   Thu Apr 25 19:00:00 2024 +0200

    Start tokens studio plugin base
2024-11-12 10:35:32 +01:00
Andrey Antukh
9d0ca089fe Merge pull request #5282 from penpot/alotor-hotfix-interactions
🐛 Fix problem creating manual overlay interactions
2024-11-11 23:55:41 +01:00
Pablo Alba
1c49dd80a4 Add from-invitation property to register-profile event 2024-11-11 17:18:53 +01:00
Pablo Alba
cbc92e9f1e Add created-by to invitations, and an event related 2024-11-11 17:00:54 +01:00
alonso.torres
2fa81474b9 🐛 Fix problem creating manual overlay interactions 2024-11-11 16:06:37 +01:00
Belén Albeza
9b7d0563b9 🔧 Add rustfmt to the devenv 2024-11-11 15:25:31 +01:00
Pablo Alba
e1e13bcfb1 Fix a viewer can drop a .penpot file on dashboard 2024-11-11 13:19:30 +01:00
Pablo Alba
134c23c70c Add a help icon to plugins menu items disabled by viewer role 2024-11-11 13:08:52 +01:00
Andrey Antukh
e369b70aeb Merge pull request #5279 from penpot/alotor-hotfix-grid-problem
🐛 Fix problem with grid layout ordering after moving
2024-11-11 12:48:40 +01:00
alonso.torres
c3970255e6 🐛 Fix problem with grid layout ordering after moving 2024-11-11 12:34:07 +01:00
Andrey Antukh
7823eaf890 📎 Update changelog 2024-11-11 12:08:49 +01:00
Pablo Alba
c89b6e2d6d Add error control on plugins permissions peek 2024-11-11 09:07:39 +01:00
Andrey Antukh
0d08549a04 🐛 Fix regression on sm/vec and sm/set schemas
Introduced in previous commits
2024-11-08 19:50:59 +01:00
Andrey Antukh
960f095c1b Merge pull request #5261 from penpot/palba-viewer-and-plugins
 Integrate viewer role with plugin menus and popup
2024-11-08 10:49:18 +01:00
Pablo Alba
d9eff00a71 Integrate viewer role with plugin menus and popup 2024-11-08 10:37:57 +01:00
Belén Albeza
7b196e1ca5 Merge pull request #5235 from penpot/azazeln28-handle-webgl-context
🎉 Handle WebGL Context
2024-11-08 09:38:45 +01:00
Alejandro
0981517bc6 Merge pull request #5263 from penpot/niwinz-bugfix-3
 Prevent logging EOF exceptions on SSE responses
2024-11-08 07:39:04 +01:00
Alejandro
8ae29ceaa2 Merge pull request #5256 from penpot/niwinz-bugfix-2
Fix incorrect behavior of ::sm/vec and ::sm/set decoder
2024-11-08 07:30:15 +01:00
Andrey Antukh
ec0079461e Merge pull request #5262 from penpot/palba-add-libraries-dialog-event
 Send event when an user opens a modal
2024-11-07 20:52:52 +01:00
Andrey Antukh
9eaa55b711 Prevent logging EOF exceptions on SSE responses
They are not necessary and they are pretty common, because
the user can interrupt the connection at any time.
2024-11-07 20:50:24 +01:00
Andrey Antukh
0c4b1cc4fc 📎 Update yarn.lock with text-editor dependency change 2024-11-07 20:24:33 +01:00
Edgars Andersons
5501859fa6 🌐 Add translations for: Latvian.
Currently translated at 99.5% (1447 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/lv/
2024-11-07 17:00:30 +01:00
Pablo Alba
70a1a7a5ea Send event when an user opens a modal 2024-11-07 16:27:16 +01:00
Andrey Antukh
96f8832bcf Merge pull request #5260 from penpot/azazeln28-fix-text-editor-selection-issue
🐛 Fix text editor bug
2024-11-07 13:50:32 +01:00
AzazelN28
0b54215b84 🐛 Fix text editor bug 2024-11-07 13:06:34 +01:00
Andrey Antukh
33ff74e534 🐛 Use portal: protocol for local npm deps resolution 2024-11-07 12:41:49 +01:00
AzazelN28
23d3661ea5 🎉 Handle WebGL context state change 2024-11-07 11:36:27 +01:00
Andrey Antukh
c3dc165c4c Merge pull request #5241 from penpot/bameda-docs-kubernetes-setup
📚 Add documentation to install with Kubernetes
2024-11-07 10:33:49 +01:00
Andrey Antukh
46a6aff4da Merge pull request #5242 from penpot/niwinz-design-tokens
🎉 Merge tokens-studio
2024-11-07 10:33:24 +01:00
Andrey Antukh
cb21eeda94 🐛 Fix build 2024-11-07 09:42:36 +01:00
Andrey Antukh
b27edb4259 🐛 Use proper schema for move-file rpc method 2024-11-06 16:29:11 +01:00
Andrey Antukh
73d85b9884 🐛 Fix incorrect behavior of ::sm/vec and ::sm/set decoder 2024-11-06 16:29:11 +01:00
David Barragán Merino
5a3619c737 📚 Add documentation to install with Kubernetes 2024-11-06 14:55:41 +01:00
Andrey Antukh
dc41fe7616 Merge pull request #5226 from penpot/palba-rename-layers
🎉 Rename selected layer via shortcut and context menu option
2024-11-06 09:49:56 +01:00
Pablo Alba
227f06c1ec Merge pull request #5255 from penpot/niwinz-bugfix-1
🐛 Fix null pointer exception on validating nil with number schema
2024-11-06 09:36:14 +01:00
Pablo Alba
48c41df054 🎉 Rename selected layer via shortcut and context menu option 2024-11-06 09:22:38 +01:00
Andrey Antukh
946dac3c9f 🐛 Fix NPE on number schemas
Mainly, without this fix, happens the following:

user=> (sm/validate [::sm/int {:min 0}] nil)
Execution error (NullPointerException) at app.common.schema/fn$fn (schema.cljc:692).
Cannot invoke "Object.getClass()" because "x" is null

And it should return `false` without an exception.
2024-11-06 09:15:06 +01:00
Andrey Antukh
b160ba1793 📎 Update .gitignore 2024-11-06 09:14:47 +01:00
Andrey Antukh
b86f2ba90d Merge pull request #5246 from penpot/luis-fix-updated-library-tab
🐛 Fix selected tab when updated library
2024-11-06 08:59:01 +01:00
Edgars Andersons
bf5a7e20d9 🌐 Add translations for: Latvian.
Currently translated at 98.0% (1424 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/lv/
2024-11-05 18:00:18 +01:00
Andrés Moya
3393963363 🔧 Apply feature flag to measures inputs 2024-11-05 16:22:20 +01:00
Andrés Moya
e641e93fd5 🐛 Fix sidebar tabs when there are no design tokens 2024-11-05 15:08:09 +01:00
Andrés Moya
99fcd3556e 🔧 Disable tokens in dev env by default 2024-11-05 14:21:09 +01:00
Andrey Antukh
b82679deaf 🎉 Merge tokens-studio 2024-11-05 14:21:09 +01:00
Andrey Antukh
0cd446421d 🐛 Fix some issues with vendored libraries and build process
related to how package.json is defined and how modules
are exported
2024-11-05 14:18:51 +01:00
Andrey Antukh
6014612046 Merge pull request #5252 from penpot/hiru-fix-manage
🐛 Fix merge error in manage script
2024-11-05 13:52:03 +01:00
Andrés Moya
eb211c0c8e 🐛 Fix merge error in manage script 2024-11-05 13:48:46 +01:00
Andrey Antukh
e6a9e27802 Merge remote-tracking branch 'origin/staging' into develop 2024-11-05 09:10:14 +01:00
Andrey Antukh
33d51a51d1 📚 Update changelog 2024-11-04 17:29:52 +01:00
Andrey Antukh
ab4be85669 Merge pull request #5250 from penpot/alotor-hotfix-plugins-api-problem
🐛 Fix problem with promises in plugins
2024-11-04 17:27:41 +01:00
alonso.torres
6c0dce580d 🐛 Fix problem with promises in plugins 2024-11-04 17:12:45 +01:00
Andrey Antukh
4ccd84f9c4 Merge pull request #5243 from penpot/niwinz-modules-improvements-1
♻️ Refactor bundle mechanism
2024-11-04 16:47:12 +01:00
Andrey Antukh
59050a7bc6 📎 Backport frontend/package.json changes
Mainly for compatibility with the upcoming devenv changes
2024-11-04 16:16:28 +01:00
Andrey Antukh
3334fb0e99 🐛 Add migration to fix invalid pages 2024-11-04 15:34:09 +01:00
Andrey Antukh
96102fc878 Update devenv default watch command for handle libs 2024-11-04 14:31:59 +01:00
Andrey Antukh
24268bbf33 Merge pull request #5248 from penpot/palba-add-event-for-add-frame
 Add event for add-frame
2024-11-04 14:25:19 +01:00
Pablo Alba
cd3f8f0c43 Add event for add-frame 2024-11-04 12:56:34 +01:00
Andrey Antukh
d3a8954605 Merge pull request #5247 from penpot/alotor-fix-plugin-problem
🐛 Fix problem with plugins path positioning
2024-11-04 12:16:25 +01:00
alonso.torres
1cda61e230 🐛 Fix problem with plugins path positioning 2024-11-04 11:02:04 +01:00
luisddm
7f93060872 🐛 Fix selected tab when updated library 2024-11-04 09:23:20 +01:00
Edgars Andersons
c3ef12f145 🌐 Add translations for: Latvian.
Currently translated at 95.3% (1385 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/lv/
2024-11-02 14:00:19 +00:00
Andrey Antukh
39106c1e14 Improve e2e performance on CI 2024-11-01 10:04:03 +01:00
Andrey Antukh
607deb31dc ♻️ Refactor bundle mechanism
Mainly leave shadow-cljs for build cljs stuff and use esbuild
for bundle all js dependencies, completly avoiding all possible
incompatibility issues between js libraries and google closure
compiler.
2024-11-01 10:04:03 +01:00
Linerly
9a35c04bf0 🌐 Add translations for: Indonesian.
Currently translated at 100.0% (1453 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/id/
2024-11-01 07:04:40 +01:00
Alejandro
aca3e3db4f Merge pull request #5237 from penpot/niwinz-hotfix-2
🐛 Fix incorrect thumbnail lookup on dashboard project view
2024-10-31 16:12:22 +01:00
Andrey Antukh
74f9166f3d Merge pull request #5238 from penpot/bameda-manage-build-docs-bundle
🎉 add command to build docs bundle
2024-10-30 23:15:22 +01:00
David Barragán Merino
977a2090fb 🎉 add command to build docs bundle 2024-10-30 19:17:04 +01:00
Andrey Antukh
14e6ea9393 Merge pull request #5236 from penpot/palba-testab-templates-link2
🎉 Add test A/B for add a link to the libraries page
2024-10-30 16:44:17 +01:00
Andrey Antukh
3eb35f0aa6 🐛 Fix incorrect thumbnail lookup on dashboard project view
That causes a repeated generation of thumbnails on each page
view instead of reusing already generated thumbnails.
2024-10-30 16:19:16 +01:00
Pablo Alba
92b7a35c58 🎉 Add test A/B for add a link to the libraries page 2024-10-30 16:13:05 +01:00
Andrey Antukh
366bca5f93 Merge remote-tracking branch 'origin/staging' into develop 2024-10-30 13:50:20 +01:00
Andrey Antukh
99807b4cd4 Merge pull request #5231 from penpot/bameda-merge-docs-repo
📚 Merge repository penpot/penpot-docs
2024-10-30 13:46:37 +01:00
Andrey Antukh
97a1bf15ef Improve how topic is managed on ws notifications 2024-10-30 13:39:38 +01:00
Andrey Antukh
9409078069 Add usage quotes for snapshots 2024-10-30 13:39:38 +01:00
Andrey Antukh
5b35cf7456 Add minor improvements to circleci config 2024-10-30 13:39:38 +01:00
Andrey Antukh
a9d3dfab1a Use schema instead of spec for validate worker submit options 2024-10-30 13:39:38 +01:00
Andrey Antukh
32126d1874 ♻️ Refactor file changes gc tasks
Make it more friendly with the current snapshoting mechanism
2024-10-30 13:39:38 +01:00
Andrey Antukh
5f4af76d28 Add permission checking to file snapshot rpc methods 2024-10-30 13:39:38 +01:00
Andrey Antukh
bff415c7cd 📎 Set yarn 4.3.1 for docs
The same as the rest of packages
2024-10-30 13:33:16 +01:00
Andrey Antukh
1d84835fd5 📎 Move .nvmrc file to the repo root 2024-10-30 13:31:24 +01:00
David Barragán Merino
88296480ec 📚 Merge penpot/penpot-docs repository 2024-10-30 13:30:02 +01:00
Pablo Alba
4f5bc77379 Update libraries links to new versions 2024-10-30 13:28:37 +01:00
Pablo Alba
b4f868be91 Update libraries links to new versions 2024-10-30 13:25:54 +01:00
Andrey Antukh
b6f35a5c1e Merge pull request #5233 from penpot/alotor-events-versions
 Add events for versions
2024-10-30 13:22:19 +01:00
alonso.torres
55fda698ec Add events for versions 2024-10-30 13:09:49 +01:00
Madalena Melo
c2467e12ba 🌐 Added translation for: Thai. 2024-10-30 12:07:45 +01:00
Denys Kisil
df74ad0e18 🌐 Add translations for: Ukrainian (ukr_UA).
Currently translated at 92.3% (1342 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
2024-10-30 12:07:31 +01:00
Linerly
e2bdc67bd2 🌐 Add translations for: Indonesian.
Currently translated at 99.5% (1447 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/id/
2024-10-30 12:07:31 +01:00
Alejandro
3932054ea6 Merge pull request #5222 from penpot/niwinz-bugfix-8
🐛 Backport bugfixes from develop to staging
2024-10-30 11:33:56 +01:00
Andrey Antukh
acf273e4e3 Merge pull request #5225 from penpot/azazeln28-panning-performance-improvement
 Improve panning code
2024-10-29 19:43:54 +01:00
Andrey Antukh
410bf7edfd Merge pull request #5229 from penpot/ladybenko-9177-viewport-wasm
 Create a separate viewport for wasm/canvas
2024-10-29 19:42:38 +01:00
Belén Albeza
345d97792f Create a separate viewport for wasm/canvas 2024-10-29 18:05:17 +01:00
Andrey Antukh
243fd17305 Merge pull request #5227 from penpot/palba-update-readme
🎉 Update readme with plugins info
2024-10-29 14:50:34 +01:00
Andrey Antukh
6b07c4179c Merge pull request #5221 from penpot/alotor-file-version
 File history versions management
2024-10-29 14:50:08 +01:00
alonso.torres
74d911f856 Add integration tests 2024-10-29 14:41:34 +01:00
alonso.torres
ecb7f0a2f6 File history versions management 2024-10-29 14:23:35 +01:00
AzazelN28
1e0e0aabf2 Improve panning code 2024-10-29 14:06:45 +01:00
Belén Albeza
fa4f2aa5cc Merge pull request #5201 from penpot/niwinz-shape-with-selrect-as-f32-array
 Shape with buffer
2024-10-29 13:47:37 +01:00
Pablo Alba
4b8febd7dc 🎉 Update readme with plugins info 2024-10-29 13:14:15 +01:00
Andrey Antukh
7cb8eb783a Merge pull request #5223 from penpot/yms-remove-gitter-badge
📎 Remove gitter and add discourse badge
2024-10-29 12:30:02 +01:00
Yamila Moreno
ef679f6722 📎 Remove gitter and add discourse badge 2024-10-29 12:00:37 +01:00
Andrey Antukh
7c73e44ab8 Add minor improvement on error reporting on shape validation 2024-10-29 11:47:47 +01:00
Andrey Antukh
e533762f33 📎 Show version on dbg header 2024-10-29 11:47:45 +01:00
Andrey Antukh
40c118df55 🐛 Fix incorrect pred composition on number schema types
Fixes the following:

  => (sm/validate (sm/schema [::sm/int {:max 10}]) nil)
  Cannot invoke "Object.getClass()" because "x" is null
2024-10-29 11:47:06 +01:00
Andrey Antukh
f43fc282d3 Increase internal s3 http client limits
Tries to improve performance of accidental spikes/bursts of
requests to s3 service. This is not a final solution to all issues
caused by unexpected burst, is a simple improvement to the current
apprach.
2024-10-29 11:47:06 +01:00
Andrey Antukh
8616e2f25c Use penpot own executor for s3 response completion executor 2024-10-29 11:47:06 +01:00
Andrey Antukh
4299fd28f0 Expose ::wrk/executor as ExecutorService instance
Instead of a plain Executor instance
2024-10-29 11:47:06 +01:00
Andrey Antukh
302ff92b31 🐛 Fix incorrect handling of EOF on s3 upload thread 2024-10-29 11:47:06 +01:00
Andrey Antukh
b62cc9c8e9 📎 Update backend scripts/repl with a default config 2024-10-29 11:47:06 +01:00
Andrey Antukh
225c2ca6e6 Add better reporting for s3 storage backend errors 2024-10-29 11:47:06 +01:00
Andrey Antukh
e5bdd852ca 🐛 Fix corner case on selection storage backend from settings
Related to how backward compatibility is handled with previous
settings.
2024-10-29 11:47:06 +01:00
Andrey Antukh
591788403a Add safer mechanism for tempfile naming
Using a uuidv8 that has strong guarranties about councurrent
ids generation that a simple random long
2024-10-29 11:47:06 +01:00
Andrey Antukh
f1b82e289d 🐛 Add retry mechanism for internal tmp file handling on s3 backend 2024-10-29 11:47:06 +01:00
Andrey Antukh
6443db64d7 Merge remote-tracking branch 'origin/staging' into develop 2024-10-29 11:42:42 +01:00
Aitor Moreno
e1fb022878 Merge pull request #5205 from penpot/niwinz-bugfix-8
🐛 General bugfixes
2024-10-29 11:32:52 +01:00
Alejandro Alonso
96bb282674 Fix many corner issues related to shape data structure change 2024-10-29 11:30:31 +01:00
Belén Albeza
4623f36042 Write shapes directly to wasm memory 2024-10-29 11:30:31 +01:00
Belén Albeza
29e0964ebc ♻️ Refactor rust/wasm code organization 2024-10-29 11:30:31 +01:00
Andrey Antukh
043c23899a 🎉 Add first impl of wasm-friendly for Shape data structure 2024-10-29 11:30:31 +01:00
Andrey Antukh
4cf5dc0791 Add minor improvement on error reporting on shape validation 2024-10-29 11:17:55 +01:00
Andrey Antukh
deaf6ef068 📎 Show version on dbg header 2024-10-29 11:17:54 +01:00
Andrey Antukh
75011ca0ff 🐛 Fix incorrect pred composition on number schema types
Fixes the following:

  => (sm/validate (sm/schema [::sm/int {:max 10}]) nil)
  Cannot invoke "Object.getClass()" because "x" is null
2024-10-29 11:17:01 +01:00
Andrey Antukh
ba3f84fd6c Increase internal s3 http client limits
Tries to improve performance of accidental spikes/bursts of
requests to s3 service. This is not a final solution to all issues
caused by unexpected burst, is a simple improvement to the current
apprach.
2024-10-29 11:17:01 +01:00
Andrey Antukh
f8c7f84c18 Use penpot own executor for s3 response completion executor 2024-10-29 11:17:01 +01:00
Andrey Antukh
7772ac0a85 Expose ::wrk/executor as ExecutorService instance
Instead of a plain Executor instance
2024-10-29 11:17:01 +01:00
Andrey Antukh
9329c2ebd9 🐛 Fix incorrect handling of EOF on s3 upload thread 2024-10-29 11:17:01 +01:00
Andrey Antukh
65f182001b 📎 Update backend scripts/repl with a default config 2024-10-29 11:17:01 +01:00
Andrey Antukh
fe83c5faea Add better reporting for s3 storage backend errors 2024-10-29 11:17:01 +01:00
Andrey Antukh
5b860ee601 🐛 Fix corner case on selection storage backend from settings
Related to how backward compatibility is handled with previous
settings.
2024-10-29 11:17:01 +01:00
Andrey Antukh
cb9839223e Add safer mechanism for tempfile naming
Using a uuidv8 that has strong guarranties about councurrent
ids generation that a simple random long
2024-10-29 11:17:01 +01:00
Andrey Antukh
15c42fba5e 🐛 Add retry mechanism for internal tmp file handling on s3 backend 2024-10-29 11:17:01 +01:00
Alejandro
f4ae8ea5ac Merge pull request #5218 from penpot/niwinz-bugfix-10
🐛 Fix issues with invalid fills
2024-10-29 08:57:50 +01:00
Alejandro
e7d7291947 Merge pull request #5196 from penpot/niwinz-remove-graaljs
⬆️ Update deps (part 1) and remove graalvm js
2024-10-29 08:48:50 +01:00
Alejandro
04121efb13 Merge pull request #5219 from penpot/niwinz-parallel-circleci
🎉 Add parallel test jobs configuration for CircleCI
2024-10-29 07:50:44 +01:00
Andrey Antukh
d9310d651a 🐛 Fix exception on adding animation to an interraction
Happens when an animation is added to a just created interaction
and then changed to other animation type. Bug is caused by missing
dependency on react handlers.
2024-10-28 18:21:02 +01:00
Andrey Antukh
6b817d102b 🐛 Add migration for a fix of invalid fills 2024-10-28 18:04:27 +01:00
Andrey Antukh
08a9371322 🐛 Use proper ::sm/int schema type on color and shape schemas 2024-10-28 18:04:25 +01:00
Andrey Antukh
32b9134722 🎉 Add parallel test jobs configuration for circleci 2024-10-28 16:28:08 +01:00
Andrey Antukh
8b60200ec6 Merge remote-tracking branch 'origin/staging' into develop 2024-10-28 11:39:42 +01:00
elhombretecla
7155b6a191 Update README.md
Adds plugins text
2024-10-28 11:30:35 +01:00
Yamila Moreno
f96da090d6 📎 Fix readme badges 2024-10-28 11:07:40 +01:00
Andrey Antukh
a57a772394 Merge pull request #5216 from penpot/yms-fix-readme-badges
📎 Fix readme badges
2024-10-28 11:07:03 +01:00
Andrey Antukh
e9f6eefaeb Merge pull request #5198 from penpot/palba-testab-share-from-workspace
🎉 Add A/B test to start directly at the workspace
2024-10-28 11:06:42 +01:00
Yamila Moreno
4188f074ca 📎 Fix readme badges 2024-10-28 10:05:35 +01:00
Andrey Antukh
e0a4ec8b87 Merge pull request #5207 from penpot/palba-viewer-role-can-unpublish
🐛 Fix view role user have menu option for unpublish a library
2024-10-28 10:04:28 +01:00
Pablo Alba
122acb3eee 🐛 Fix view role user have menu option for unpublish a library 2024-10-28 09:48:40 +01:00
Pablo Alba
9728f1ba80 🐛 Fix unexpected failure on plugins-menu and info-menu 2024-10-28 09:48:33 +01:00
Andrey Antukh
93ca268ee7 Merge pull request #5203 from penpot/palba-rename-welcome-file
 Rename welcome file
2024-10-26 15:11:51 +02:00
Pablo Alba
b852dc86c0 🎉 Add A/B test to start directly at the workspace 2024-10-25 17:45:47 +02:00
Aitor Moreno
361b5decbe Merge pull request #5191 from penpot/palba-testab-templates-link
🎉 Add test A/B for add a link to the libraries page
2024-10-25 15:16:22 +02:00
Aitor Moreno
cd3c2b4bf7 Merge pull request #5160 from penpot/code-challenge-lambda-world-2024
:neckbeard: Winner of Code Challenge Lambda World 2024
2024-10-25 14:49:03 +02:00
Aitor Moreno
5718c1f287 Merge pull request #5200 from penpot/alotor-performance-improvement
 Improved performance for root frame movement
2024-10-25 14:48:10 +02:00
Andrey Antukh
8d8f203b8a Merge pull request #5204 from penpot/alotor-bugfix-import
🐛 Fix problem with imports
2024-10-25 14:32:41 +02:00
alonso.torres
f40ffacfbd 🐛 Fix problem with imports 2024-10-25 13:34:40 +02:00
Andrey Antukh
d7caf5ed1a Merge pull request #5202 from penpot/yms-pin-latest-open-source-redis-version
⬆️ Pin redis@7.2 in docker-compose, as it's the latest open source version
2024-10-25 13:02:24 +02:00
Yamila Moreno
aa7cbc9f08 ⬆️ Pin redis@7.2 in docker-compose
It's the latest open source version
2024-10-25 12:29:31 +02:00
Pablo Alba
afb5ab7430 Rename welcome file 2024-10-25 12:23:35 +02:00
Andrey Antukh
c2ba7cdbc7 Merge remote-tracking branch 'origin/staging' into develop 2024-10-25 10:12:38 +02:00
alonso.torres
2f8be445d6 Improved performance for root frame movement 2024-10-24 17:00:16 +02:00
luisddm
ae435f67a5 🐛 Fix intentation and ellipsis in the left sidebar when inspector is activated in viewer mode 2024-10-24 14:37:39 +02:00
Belén Albeza
09e1bac41c Merge pull request #5190 from penpot/ladybenko-9046-emscripten
🎉 Switch new renderer to Emscripten (from wasm-bindgen)
2024-10-23 17:44:44 +02:00
Andrey Antukh
fc7fe41c98 Rename to render-wasm and make it load using dynamic import 2024-10-23 17:18:04 +02:00
Eva Marco
c7308ce634 Merge pull request #5181 from penpot/luis-replace-icon-buttons-workspace
♻️ Replace buttons on workspace
2024-10-23 16:13:51 +02:00
luisddm
e45fa1380d ♻️ Replace buttons on workspace
♻️ Replace buttons on workspace

♻️ Format files

🐛 Fix pull request issues
2024-10-23 14:46:47 +02:00
Belén Albeza
e4eb80f643 🎉 Switch new renderer to Emscripten (from wasm-bindgen) 2024-10-23 13:14:17 +02:00
Andrey Antukh
cc6e071f48 ♻️ Remove all usage of graalvm js runtime
And replace it with a commandline call to nodejs
for execute a custom svgo based command line script.
2024-10-22 23:30:56 +02:00
Andrey Antukh
283ea16627 Merge pull request #5197 from penpot/luis-fix-inspector-indentation-ellipsis-viewer
🐛 Fix intentation and ellipsis in the left sidebar when inspector is activated in viewer mode
2024-10-22 20:24:28 +02:00
Andrey Antukh
15b33488c6 ⬆️ Update exporter dependencies 2024-10-22 20:23:38 +02:00
Andrey Antukh
0e2be44e17 ⬆️ Update frontend dependencies 2024-10-22 20:23:38 +02:00
Andrey Antukh
f949649ba3 ⬆️ Update backend dependencies 2024-10-22 20:23:38 +02:00
Andrey Antukh
b31a6f33a5 ⬆️ Update dependencies on common 2024-10-22 20:23:38 +02:00
Andrey Antukh
51ecbf15a9 ⬆️ Update yetti and http server dependency 2024-10-22 20:23:38 +02:00
Andrey Antukh
0fd783e65e Make nodejs available on backend docker image
Used for execute svgo-cli.js script
2024-10-22 20:23:38 +02:00
Andrey Antukh
1da5fd106a 🐛 Fix future linter issue on common schema ns 2024-10-22 20:23:34 +02:00
luisddm
17aafe6775 🐛 Fix intentation and ellipsis in the left sidebar when inspector is activated in viewer mode 2024-10-22 18:47:01 +02:00
Andrey Antukh
d89dfc5e30 Merge pull request #5194 from penpot/alotor-bugfix-grid
🐛 Fix problem with swap components on grid
2024-10-22 17:31:31 +02:00
alonso.torres
cd586c81ee 🐛 Fix problem with swap components on grid 2024-10-22 16:14:14 +02:00
Andrés Moya
9064b9f849 🐛 Fix file builder hangs on export 2024-10-22 11:14:47 +02:00
Pablo Alba
9fc8760dc5 🎉 Add test A/B for add a link to the libraries page 2024-10-21 17:45:54 +02:00
Andrey Antukh
16e1e01234 Merge pull request #5171 from penpot/palba-fix-rulers-on-view-only
🐛 Fix you can manage rulers on view mode
2024-10-21 17:29:40 +02:00
Andrey Antukh
22800e71df Merge pull request #5189 from penpot/palba-bugs-viewer-role
Issues on viewer role
2024-10-21 17:28:56 +02:00
Pablo Alba
352b09a891 🐛 Fix bad order in roles dropdown 2024-10-21 17:05:53 +02:00
Pablo Alba
68f560e29b 🐛 Fix corner case of change rol to viewer when editing a text 2024-10-21 17:05:53 +02:00
Pablo Alba
4622dd0e0d 🐛 Fix bad team permissions showing on team page for viewer 2024-10-21 16:06:38 +02:00
Andrey Antukh
ed822d9f46 ⬆️ Update text editor bundle 2024-10-21 12:36:01 +02:00
Andrey Antukh
c1359d9677 💄 Add minor improvement to doc formatting 2024-10-21 12:36:01 +02:00
Andrey Antukh
ac33df2054 🐛 Remove plugin data from binfile v3 export 2024-10-21 12:36:01 +02:00
Andrey Antukh
b800fcafb4 💄 Add minor improvements to dashboard project menu 2024-10-21 12:36:01 +02:00
Andrey Antukh
6b997928e5 💄 Add minor improvements to dashboard file menu 2024-10-21 12:36:01 +02:00
Andrey Antukh
ee533e2644 Prevent warning of button inside button on dashboard 2024-10-21 12:36:01 +02:00
Andrey Antukh
d6da8afdce Add improved abstraction for team permissions
Relevant changes:
- replace user-viewer? with can-edit removing many double
  negations on the code
- always use team permissions making the permissions access uniform
  around all the code
- expose team permissions to ui tree through ctx/team-permissions
  context
2024-10-21 12:36:01 +02:00
Andrey Antukh
b3fcbd91e4 🐛 Remove the usage of namespaced keywords on toplevel global state
Because debuging the global state value becomes dificult when
exist a name clash on namespaced keywords and not namespaced keywords.
2024-10-21 12:36:01 +02:00
Andrey Antukh
51c6abb261 Disable rename support on the ui for binfile-v3
Not supported on backend
2024-10-21 12:36:01 +02:00
Andrey Antukh
43b86d403c Remove unused props from binfile-v3 progress report message 2024-10-21 12:36:01 +02:00
Andrey Antukh
6a1399dd50 Merge remote-tracking branch 'origin/staging' into develop 2024-10-21 11:20:27 +02:00
Belén Albeza
fe6c9f24d3 🐛 Fix edit grid unit dropdown being clipped 2024-10-21 10:15:57 +02:00
Andrey Antukh
6e62472759 Merge pull request #5172 from penpot/niwinz-binfile-v3
🎉 Add binfile-v3 export/import file format
2024-10-18 17:34:20 +02:00
Andrey Antukh
6c9f4a8fd5 ♻️ Reorganize files export and import related code on frontend 2024-10-18 17:19:29 +02:00
Andrey Antukh
8618cb950f 🎉 Add binfile-v3 export/import file format 2024-10-18 17:19:29 +02:00
Andrey Antukh
4fb5d3fb20 🐛 Add missing :key prop on legacy-zip format exportation component 2024-10-18 17:19:29 +02:00
Andrey Antukh
e0669ebbf8 Add minor improvements to schema and spec namespaces 2024-10-18 17:19:29 +02:00
Andrey Antukh
015fd5bc3a Expose a list of valid buckets on main storage ns 2024-10-18 17:19:29 +02:00
Andrey Antukh
88d85706ad ♻️ Refactor context-menu component 2024-10-18 17:19:29 +02:00
Andrey Antukh
782d733bc9 Improve error response formatting 2024-10-18 17:19:29 +02:00
Andrey Antukh
1318019ccb Merge remote-tracking branch 'origin/staging' into develop 2024-10-18 17:19:10 +02:00
Pablo Alba
fe314cf146 🐛 Fix you can manage rulers on view mode 2024-10-18 14:03:46 +02:00
Andrey Antukh
97a880c946 Merge pull request #5179 from penpot/alotor-bugfixing-5
Alotor bugfixing 5
2024-10-18 14:00:53 +02:00
alonso.torres
df66955594 🐛 Fix problem with shadows and frames in Safari 2024-10-18 11:52:41 +02:00
alonso.torres
07f055bd49 🐛 Fix problem when duplicating board with guide 2024-10-18 11:52:41 +02:00
alonso.torres
22d5b125bd 🐛 Fix problem with layers overflowing panel 2024-10-18 11:52:40 +02:00
Andrey Antukh
1aa2c0f9de Merge pull request #5135 from penpot/palba-eva-viewer-role
  Add viewer role
2024-10-18 10:31:40 +02:00
Pablo Alba
bd08e99080 ♻️ Clean up and refactors of viewer role 2024-10-18 10:12:59 +02:00
Pablo Alba
66530ca868 ♻️ Minor fixes on viewer role on workspace 2024-10-17 16:29:41 +02:00
alonso.torres
ef3b4a5895 🐛 Fix problem with plugins icons 2024-10-17 14:51:01 +02:00
Andrey Antukh
b4c2f2ecaa Merge pull request #5170 from penpot/palba-fix-missing-permisions-on-file-etag-cache
🐛 Fix missing permissions on file cache
2024-10-17 11:58:10 +02:00
Andrey Antukh
a739688780 Merge remote-tracking branch 'origin/staging' into develop 2024-10-16 17:59:28 +02:00
Andrey Antukh
790f6ce4ed 💄 Add cosmetic changes to get-file rpc method 2024-10-16 17:58:04 +02:00
Andrey Antukh
40d7bb04b4 Reuse permission from rpc/cond middleware for get-file rpc method 2024-10-16 17:58:04 +02:00
Pablo Alba
22d7cfc7fa 🐛 Fix missing permissions on file cache 2024-10-16 17:58:04 +02:00
Andrey Antukh
d4c775b1f4 🐛 Fix unexpected rare condition exception on rpc cond middleware 2024-10-16 17:58:00 +02:00
Andrey Antukh
02611029fb Merge pull request #5176 from penpot/juan-relesae-notes-2.3
Relesae notes 2.3 on onboarding slides
2024-10-16 16:31:19 +02:00
Elhombretecla
14e4e6d6ea 🎉 Add release note slides for 2.3 2024-10-16 14:33:20 +02:00
Eva Marco
536c25c206 ♻️ Resolve minor errors on viewer role on dashboard 2024-10-16 10:37:52 +02:00
Pablo Alba
6fb65de100 Close menus and modals on role change 2024-10-15 13:38:46 +02:00
Eva Marco
043c4105db Add viewer only mode on webhook 2024-10-15 13:38:46 +02:00
Pablo Alba
823792339f Kick out of a team - Visibility of System Status 2024-10-15 13:38:46 +02:00
Pablo Alba
226ab7233b Add viewer role to workspace 2024-10-15 13:38:46 +02:00
Pablo Alba
cf150891df Add view mode to dashboard 2024-10-15 13:32:33 +02:00
Andrey Antukh
9170c70f2a Merge pull request #5169 from penpot/alotor-bugfixing4
🐛 Fix problem with inner strokes bounds
2024-10-15 13:02:53 +02:00
alonso.torres
83d8bf37a6 🐛 Fix problem with inner strokes bounds 2024-10-15 12:28:23 +02:00
Andrey Antukh
c841ed6419 Merge remote-tracking branch 'origin/staging' into develop 2024-10-15 09:30:03 +02:00
Andrey Antukh
1fb21d537c 🐛 Send thread-id on create-comment-thread rpc method 2024-10-15 09:29:40 +02:00
Andrey Antukh
ac80e9a1ac Respect overrides of jvm_opts on devenv bashrc file 2024-10-15 09:13:46 +02:00
Andrey Antukh
dbbb8e76ab Allow override java opts for build scripts 2024-10-15 09:13:46 +02:00
Andrey Antukh
916f055aec Merge pull request #5165 from penpot/alotor-bugfixing-3
Alotor bugfixing 3
2024-10-14 19:16:39 +02:00
alonso.torres
6d8c183160 Add plugins whitelisting for removing the disclaimer 2024-10-14 15:25:37 +02:00
alonso.torres
9d2f484aa3 🐛 Fix problem with horizontal/vertical lines and shadows 2024-10-14 15:25:37 +02:00
alonso.torres
2dc0cfdee3 🐛 Fix problem with caps and inner shadows 2024-10-14 15:25:37 +02:00
alonso.torres
a25abd0ca4 🐛 Fix percent calculation on grid layout tracks 2024-10-14 15:25:37 +02:00
alonso.torres
3a9119cf29 🐛 Add visual feedback when moving an element into a board 2024-10-14 15:25:37 +02:00
alonso.torres
c236e0765b 🐛 Fix problems with show in viewer and interactions 2024-10-14 15:25:37 +02:00
alonso.torres
f8fad95fef 🐛 Fix problem with shortcuts in text editor 2024-10-14 11:45:50 +02:00
alonso.torres
97ae295cb9 🐛 Fix problem updating layout when toggle visibility in component copy 2024-10-14 11:45:27 +02:00
Eva Marco
bd888dcde2 🐛 Fix constraints buttons 2024-10-14 11:41:26 +02:00
Andrey Antukh
784274f8ae Merge pull request #5163 from penpot/palba-bugfixing-011
Palba bugfixing 011
2024-10-14 11:40:45 +02:00
Linerly
65c1eb3a63 🌐 Add translations for: Indonesian.
Currently translated at 97.8% (1422 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/id/
2024-10-12 18:16:34 +02:00
Pablo Alba
eda6c6a4c3 🐛 Fix "Done" button on toolbar on inspect mode should go to design mode 2024-10-11 14:36:57 +02:00
Pablo Alba
7d7594818c 🐛 Fix Internal Error page: "go to your penpot" wrong design 2024-10-11 14:35:56 +02:00
Andrey Antukh
8165635fad Merge remote-tracking branch 'origin/staging' into develop 2024-10-11 12:50:58 +02:00
Andrey Antukh
7cc8f67e24 Merge pull request #5161 from penpot/niwinz-bugfix-6
🐛 Fix storybook build
2024-10-11 12:28:41 +02:00
Andrey Antukh
87fc3bbb8e 🐛 Fix storybook build 2024-10-11 12:11:37 +02:00
alonso.torres
286a834f4a Merge remote-tracking branch 'origin/staging' into develop 2024-10-11 09:13:15 +02:00
Andrey Antukh
bbb2cc972f Merge pull request #5159 from penpot/alotor-plugins-fixes-2
Plugins improvements
2024-10-11 09:04:29 +02:00
Andrés Moya
c14d28dc1e :neckbeard: Winner of Code Challenge Lambda World 2024
https://community.penpot.app/t/were-attending-the-lambda-world-conf-october-2-4th/6647/2
2024-10-10 17:20:57 +02:00
alonso.torres
6a07e6ae01 Add update plugin permission dialog 2024-10-10 17:12:39 +02:00
Andrey Antukh
556ec45efc Merge pull request #5153 from penpot/yms-improve-flags-configuration-in-docker-compose
🐳 Improve flags configuration in docker-compose
2024-10-10 16:48:57 +02:00
Andrey Antukh
754e09b0de Merge remote-tracking branch 'origin/staging' into develop 2024-10-10 16:44:58 +02:00
Yamila Moreno
308b2d95f3 🐳 Improve flags configuration in docker-compose 2024-10-10 16:13:46 +02:00
Andrey Antukh
87dfd2b3c8 🐛 Force sync update on storage before immediate refresh 2024-10-10 16:04:15 +02:00
Andrey Antukh
b0bfb8006d 💄 Add cosmetic changes to dashboard templates layer 2024-10-10 16:04:15 +02:00
Andrey Antukh
d46274abf2 Add better error reporting on zip file importation 2024-10-10 16:04:15 +02:00
Andrey Antukh
23f7889cff 💄 Add cosmetic change to create-temp-file rpc method 2024-10-10 16:04:15 +02:00
Andrey Antukh
534659cdc6 🐛 Fix flows import and export on zip format 2024-10-10 16:04:15 +02:00
alonso.torres
1e68d4ec87 Close plugin on esc button 2024-10-10 16:03:45 +02:00
alonso.torres
1779fd3e8b Fix zero case for plugins 2024-10-10 16:03:45 +02:00
alonso.torres
3c496ddd9d ⬆️ Update plugins runtime 2024-10-10 16:03:45 +02:00
Andrey Antukh
66053ae9df Merge remote-tracking branch 'origin/staging' into develop 2024-10-10 14:51:16 +02:00
Andrey Antukh
77348bb9a4 Merge pull request #5111 from penpot/bameda-docker-use-nginx-unprivileged-base-image
🐳 Use nginx-unprivileged as base image
2024-10-10 14:48:28 +02:00
David Barragán Merino
14257ae422 🐳 Change maintainer in docker images 2024-10-10 13:47:48 +02:00
David Barragán Merino
e64c956693 🐳 Use nginx-unprivileged as base image 2024-10-10 13:47:48 +02:00
David Barragán Merino
4a6b246f0f Add commands to build the docker images individually 2024-10-10 13:47:33 +02:00
Inex Code
6f7bc54a39 🌐 Add translations for: Russian.
Currently translated at 96.1% (1397 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ru/
2024-10-10 12:15:49 +02:00
Andrey Antukh
47bc9d8ef1 Merge pull request #5157 from penpot/alotor-bugfixing-2
Alotor bugfixing 2
2024-10-10 11:45:48 +02:00
alonso.torres
a3a5fe056d 📚 Update changelog 2024-10-10 11:45:16 +02:00
Eero Pitkänen
fbb3271c81 🐛 Fix dragging path points by returning closest point instead of only the distance 2024-10-10 11:45:16 +02:00
alonso.torres
ecc93d9246 🐛 Fix problem with precision on boolean calculation 2024-10-10 11:45:16 +02:00
alonso.torres
302672f5b0 🐛 Fix problem with hover layers when hidden/blocked 2024-10-10 11:45:16 +02:00
alonso.torres
4f16ea2d2d 🐛 Fix problem with stroke and filter ordering in frames 2024-10-10 11:45:12 +02:00
Andrey Antukh
b7a0b7d629 🐛 Increase feedback limits to reasonable values 2024-10-10 11:27:04 +02:00
Andrey Antukh
bd6f1bef10 🐛 Don't raise an unexpected exception on multiple-input enter
When a enter is pressed and field is empty
2024-10-10 11:27:04 +02:00
Andrey Antukh
c4941bb102 🐛 Fix unexpected exception on handling audit log on team invitations
A regression introduced in previous commits of this release
2024-10-10 11:27:04 +02:00
Andrey Antukh
b8a606a35f 🐛 Fix incorrect dependency for log-emails and smtp flags 2024-10-10 11:23:04 +02:00
Andrey Antukh
370eebeb64 🐛 Remove unused shadow config from exporter 2024-10-10 11:23:04 +02:00
Andrey Antukh
35bcb082a0 🐛 Remove data-testid usage from shape 2024-10-10 11:23:04 +02:00
Eero Pitkänen
0c8678eb87 🐛 Fix dragging path points by returning closest point instead of only the distance 2024-10-10 11:15:49 +02:00
Andrey Antukh
dd220e228e Merge pull request #5152 from penpot/alotor-fix-selection
🐛 Fix problem with selection
2024-10-09 13:50:51 +02:00
alonso.torres
7b63aa4a4f 🐛 Fix problem with selection 2024-10-09 13:34:33 +02:00
Andrey Antukh
33a07346dd 💄 Add minor cmd naming change for e2e test commands 2024-10-09 13:09:01 +02:00
Andrey Antukh
abd77559ab 🐛 Fix svg exportation with shapes with svg-unsafe characters in the name 2024-10-09 13:09:01 +02:00
Andrey Antukh
28878caca9 🐛 Fix cache issues with plugin runtime import uri 2024-10-09 13:09:01 +02:00
Andrey Antukh
74f3379b5d Merge pull request #5150 from penpot/alotor-bugfixing
Alotor bugfixing
2024-10-09 12:16:26 +02:00
alonso.torres
379770343a 🐛 Close plugin if open when installed 2024-10-09 10:50:56 +02:00
alonso.torres
6327286328 ⬆️ Update runtime 2024-10-09 09:39:47 +02:00
alonso.torres
3a2677a91a 🐛 Fix problem with shadows in text for Safari 2024-10-08 15:40:20 +02:00
alonso.torres
fcd232aa35 🐛 Fix problem with go back button on error page 2024-10-08 15:40:20 +02:00
alonso.torres
5dd14b929a 📚 Update changelog 2024-10-08 15:36:01 +02:00
alonso.torres
f194e2c1c6 📚 Updates changelog 2024-10-08 15:34:41 +02:00
Andrey Antukh
ea6731e22b Add EOF handling on sse response helper 2024-10-08 15:30:33 +02:00
Andrey Antukh
002b1679c3 ♻️ Clean assertion and schema chechking API 2024-10-08 15:30:33 +02:00
Andrey Antukh
45f3a67950 Relax transaction requeriments for team invitation creation 2024-10-08 14:51:14 +02:00
Andrey Antukh
c6917bb0cf Relax transaction requirements on create-team rpc method 2024-10-08 14:51:14 +02:00
Andrey Antukh
f777845d14 Relax transaction requirement on comment thread creation rpc method 2024-10-08 14:51:14 +02:00
Andrey Antukh
a1f5bcae80 ♻️ Add better ergonomics for the internal quotes API 2024-10-08 14:51:14 +02:00
Andrey Antukh
3e11b4aa74 Add facility for wrap a rpc method in a db transaction 2024-10-08 14:51:14 +02:00
Aitor Moreno
4f48236fee Merge pull request #5141 from penpot/niwinz-enhancements-text-editor-v2-2
 Add minor improvements to text editor v2 events handling
2024-10-07 12:58:17 +02:00
Andrey Antukh
ffadf29ad7 Add minor improvements to text editor v2 events handling
Also updates the editor code to the latest version
2024-10-07 10:13:21 +02:00
Aitor Moreno
352efcb610 Merge pull request #5139 from penpot/niwinz-enhancements-text-editor-v2
 Add minor improvements for text-editor-v2
2024-10-04 09:38:50 +02:00
Andrey Antukh
334e83479f Add minor improvements for text-editor-v2 2024-10-03 09:51:04 +02:00
Alejandro Alonso
476eedbd2c Merge remote-tracking branch 'origin/staging' into develop 2024-10-03 07:19:53 +02:00
Alejandro
ae7e28b71b Merge pull request #5137 from penpot/niwinz-enhancements-1
 Add limits for invitation creation RPC method
2024-10-03 07:18:18 +02:00
Andrey Antukh
be30174a49 Add limits for team invitations 2024-10-02 16:05:33 +02:00
Alejandro
8373654f80 Merge pull request #5134 from penpot/alotor-hotfix-2.3
Alotor hotfix 2.3
2024-10-02 13:57:05 +02:00
alonso.torres
471c636580 🐛 Fix visual problem with the font-size dropdown in assets 2024-10-02 13:45:50 +02:00
alonso.torres
635c6efe42 🐛 Fix problem with Ctrl+F shortcut on the dashboard 2024-10-02 13:45:30 +02:00
Alejandro
d570048f78 Merge pull request #5132 from penpot/niwinz-bugfix-1
🐛 Fix issues on migration 55
2024-10-02 13:36:43 +02:00
Andrey Antukh
dcc49dafd3 Merge pull request #5029 from penpot/azazeln28-refactor-text-editor
♻️ Refactor text editor
2024-10-02 11:05:26 +02:00
AzazelN28
7398f7ce0d ♻️ Replace Draft.js with custom editor 2024-10-01 22:31:16 +02:00
Stas Haas
06fadc45f2 🌐 Add translations for: German.
Currently translated at 98.6% (1433 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-10-01 17:16:03 +02:00
IsCycleBai
f633a673c4 🌐 Add translations for: Chinese (Simplified Han script).
Currently translated at 94.9% (1379 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/zh_Hans/
2024-10-01 17:16:03 +02:00
Andrey Antukh
76479a2486 🐛 Fix page background migration 2024-10-01 16:44:54 +02:00
Andrey Antukh
31f62dcc12 🐛 Fix incorrect flows conversion on migration 55 2024-10-01 16:34:22 +02:00
Andrey Antukh
3d7df5b005 Merge pull request #5115 from penpot/alotor-plugins
Plugins update
2024-10-01 12:53:03 +02:00
alonso.torres
c16a116707 Modifications after review 2024-10-01 11:57:52 +02:00
alonso.torres
f7f06f59ce ⬆️ Upgrade plugin runtime 2024-10-01 09:34:45 +02:00
alonso.torres
d1277afee6 New plugin install workflow 2024-09-30 16:03:40 +02:00
alonso.torres
a510d01136 Plugins api changes 2024-09-30 15:49:46 +02:00
alonso.torres
0e651df65f Updates permissions for comments 2024-09-30 15:20:34 +02:00
alonso.torres
758e0458bc 🐛 Fix problem when returning parent proxy 2024-09-30 15:20:34 +02:00
alonso.torres
e18b4666ba Update permissions dialog 2024-09-30 15:20:34 +02:00
Alejandro Alonso
864088eecd Merge remote-tracking branch 'origin/staging' into develop 2024-09-30 09:38:11 +02:00
Pablo Alba
0b39318b33 🐛 Fix request dialog is shown in all errors 2024-09-30 09:36:41 +02:00
Alejandro
d5a9961ec8 Merge pull request #5124 from penpot/eva-move-tab-switcher
♻️  Move tab-switcher to its own folder inside DS
2024-09-30 09:29:15 +02:00
Alejandro
7dac7de365 Merge pull request #5123 from penpot/palba-change-emails-footer
 Update emails footer
2024-09-30 07:11:27 +02:00
Alejandro
dd0721e91e Merge pull request #5126 from penpot/palba-fix-show-request-on-all-errors
🐛 Fix request dialog is shown in all errors
2024-09-30 06:19:58 +02:00
Amerey.eu
e8d2c5e30d 🌐 Add translations for: Czech.
Currently translated at 99.5% (1447 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/cs/
2024-09-28 08:15:50 +02:00
Pablo Alba
21fde2e991 🐛 Fix request dialog is shown in all errors 2024-09-27 10:38:24 +02:00
Eva Marco
ca1893164d Add the undefied option to props schema enums 2024-09-26 17:39:52 +02:00
Eva Marco
b619ac3e08 ♻️ Move tab-switcher to its own folder inside DS 2024-09-26 17:39:45 +02:00
Tatsuto Yamamoto
2992ec064f 🌐 Add translations for: Japanese.
Currently translated at 16.5% (241 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ja/
2024-09-26 17:15:50 +02:00
Cesar Andres Estrella Paredes
911281b7b9 🌐 Add translations for: Spanish.
Currently translated at 99.3% (1444 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/es/
2024-09-26 17:15:49 +02:00
Belén Albeza
d7eb86c86d Merge pull request #5095 from penpot/eva-update-ds-components
♻️ Update colors and icons
2024-09-26 12:00:45 +02:00
Pablo Alba
6c4f216da8 Update emails footer 2024-09-26 09:45:42 +02:00
Alejandro Alonso
f786a00e89 Merge remote-tracking branch 'origin/staging' into develop 2024-09-25 11:35:41 +02:00
Alejandro
47cecb2ac4 Merge pull request #5119 from penpot/eva-add-props
  Add shema prop
2024-09-25 11:31:57 +02:00
Eva Marco
5d6ceec803 Add shema prop 2024-09-25 11:07:40 +02:00
Alejandro Alonso
bec11220e3 🐛 Fix storage typo 2024-09-25 10:41:55 +02:00
Alejandro Alonso
9b802e1c7d Merge remote-tracking branch 'origin/staging' into develop 2024-09-24 14:27:20 +02:00
Alejandro
16cf16c422 Merge pull request #5114 from penpot/superalex-fix-fetch-profile-exception
🐛 Fix fetch profile exception
2024-09-24 14:24:56 +02:00
Alejandro Alonso
4e1eee197e 🐛 Fix fetch profile exception 2024-09-24 14:13:46 +02:00
Alejandro
91c8af9e38 Merge pull request #5108 from penpot/palba-fix-login-redirect
🐛 Fix bad redirect on new oops page with penpot login
2024-09-24 11:27:04 +02:00
Pablo Alba
58593a9428 🐛 Fix bad redirect on new oops page with penpot login 2024-09-24 10:32:57 +02:00
Alejandro Alonso
21aa8b0703 Merge remote-tracking branch 'origin/staging' into develop 2024-09-24 09:42:56 +02:00
Eva Marco
17cf57f7ca Merge pull request #5113 from penpot/superalex-fix-show-in-assets-panel
🐛 Fix show in assets panel
2024-09-24 09:38:32 +02:00
Alejandro Alonso
f7cfe36f37 🐛 Fix show in assets panel 2024-09-24 08:49:52 +02:00
Alejandro
c26f909565 Merge pull request #5110 from penpot/eva-fix-code-block-height
🐛 Fix code block height
2024-09-24 06:54:44 +02:00
Eva Marco
6db7fe5f7b 🐛 Fix code block height 2024-09-23 17:03:25 +02:00
Pablo Alba
a207114d95 Merge pull request #5109 from penpot/hiru-fix-swap-inside-group
🐛 Fix error when swapping a copy that is the only child of a group
2024-09-23 15:12:55 +02:00
Eva Marco
b8299a5ea5 🐛 Fix create team without invitations on onboarding 2024-09-23 15:09:43 +02:00
Andrés Moya
1fa461e996 🐛 Fix error when swapping a copy that is the only child of a group 2024-09-23 15:01:01 +02:00
Alejandro
2e3745099b Merge pull request #5107 from penpot/alotor-remove-export-option
🐛 Removed "merge assets" option from export
2024-09-23 13:22:56 +02:00
Pablo Alba
03ebeb0657 🐛 Fix session storage entry name 2024-09-23 12:15:49 +02:00
alonso.torres
6892cffe54 🐛 Removed "merge assets" option from export 2024-09-23 12:13:33 +02:00
Alejandro
19a613e90c Merge pull request #5105 from penpot/superalex-merge-conflicts-2
Merge conflicts
2024-09-23 10:57:33 +02:00
Alejandro Alonso
7fe95f218b 🐛 Fix logged in redirect 2024-09-23 10:36:59 +02:00
Alejandro Alonso
a1fc785771 Merge remote-tracking branch 'origin/staging' into superalex-merge-conflicts-2 2024-09-23 10:08:06 +02:00
Alejandro Alonso
e0034dc205 🐛 Fix onboarding edn urls 2024-09-23 06:30:19 +02:00
Alejandro
bd9eab08b7 Merge pull request #5101 from penpot/palba-migrate-templates-v2
 Update templates links to binary v2
2024-09-23 06:12:15 +02:00
Denys Kisil
e2e6e7db85 🌐 Add translations for: Ukrainian (ukr_UA).
Currently translated at 91.2% (1326 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
2024-09-20 12:02:00 +02:00
Pablo Alba
b5121657ee Update templates links to binary v2 2024-09-18 16:23:12 +02:00
Andrey Antukh
4f04dbc294 🐛 Fix frame flows issues related to the refactor 2024-09-18 12:15:12 +02:00
alonso.torres
2b2a84da64 🐛 Fix problem with frame guides 2024-09-18 12:15:12 +02:00
Andrey Antukh
21dd9a260c 📎 Rename common files changes test namespace 2024-09-18 12:15:12 +02:00
Andrey Antukh
7b9b5bafc1 🔥 Remove duplicated test 2024-09-18 12:15:12 +02:00
Andrey Antukh
41ebba6ce0 Add generative tests for flows and saved-grids 2024-09-18 12:15:12 +02:00
Andrey Antukh
61446592b3 Move generative test related code to a separated ns 2024-09-18 12:15:12 +02:00
Andrey Antukh
b82c6326cf Add better error reporting on changes validation 2024-09-18 12:15:12 +02:00
Andrey Antukh
a2f466810b ♻️ Add minor refactor on set-plugin-data change 2024-09-18 12:15:12 +02:00
Andrey Antukh
1bd1782d66 ♻️ Add better reporting for generative tests 2024-09-18 12:15:12 +02:00
Andrey Antukh
ea6a1c05fa 🐛 Fix incorrect assignation of plugin data on page data structure 2024-09-18 12:15:12 +02:00
Andrey Antukh
4f84e77b10 Add generative tests for set-guide change 2024-09-18 12:15:12 +02:00
Andrey Antukh
fa75a3539f 📎 Rename shape decode encode test file 2024-09-18 12:15:12 +02:00
Andrey Antukh
fa12d9785a Add tests for basic obj crud change operations
Restored and adapted from already existing commented code
2024-09-18 12:15:12 +02:00
Andrey Antukh
c578e31ae2 📎 Update some docstrings on common/schema ns 2024-09-18 12:15:12 +02:00
Andrey Antukh
749c369080 Add less verbose shape validation 2024-09-18 12:15:12 +02:00
Andrey Antukh
4ad4057878 ♻️ Refactor page options data structure 2024-09-18 12:15:12 +02:00
Andrey Antukh
2dea0b52ed Merge pull request #5077 from penpot/ladybenko-8638-docker-rust
Set up devenv for Rust
2024-09-17 17:30:38 +02:00
Aitor Moreno
ca257d1caf Merge pull request #5097 from penpot/eva-fix-arrow-keys-tabs
🐛  Fix arrow key movement on tabs
2024-09-17 17:23:32 +02:00
Aitor Moreno
e164692391 Merge pull request #5098 from penpot/eva-fix-desing-panel
🐛  Fix path side panel options
2024-09-17 17:22:21 +02:00
Eva Marco
b58edea544 🐛 Fix path side panel options 2024-09-17 17:00:40 +02:00
Eva Marco
9a587c91a8 🐛 Fix arrow key movement on tabs 2024-09-17 16:36:44 +02:00
Belén Albeza
7590a7ce4d Merge pull request #5072 from penpot/eva-add-schema-to-ds-components
 Add schema validation to all DS components
2024-09-17 16:22:22 +02:00
Aitor Moreno
aae1571a5c Merge pull request #5096 from penpot/alotor-bugfixes
Bugfixes
2024-09-17 16:14:59 +02:00
alonso.torres
ebaf30727c 🐛 Fix copy/paste images in Safari 2024-09-17 15:38:18 +02:00
Belén Albeza
884ceb052b Use dynamic import for wasm module 2024-09-17 14:52:27 +02:00
Belén Albeza
cc7ed497e8 🎉 Enable conditional use of wasm module 2024-09-17 14:51:55 +02:00
Belén Albeza
cd6a739abb 🔧 Add dummy rust project + build scripts with wasm-pack 2024-09-17 14:51:55 +02:00
Belén Albeza
f0cecfd517 🔧 Install Rust+Cargo in devenv 2024-09-17 14:51:55 +02:00
alonso.torres
f5f255e2d5 🐛 Fix problem with comments max length 2024-09-17 14:18:51 +02:00
Eva Marco
5ffa56be3d ♻️ Update select background color on input 2024-09-17 14:11:50 +02:00
Alejandro
e65c0d9f48 Merge pull request #5088 from penpot/niwinz-bugfix-2
🐛 Fix issues related to invalid colors inserted on shape shadow
2024-09-17 13:58:43 +02:00
Eva Marco
076cb0e35b Add schema validation to all DS components 2024-09-17 13:43:35 +02:00
Andrey Antukh
2a90ca6546 Merge pull request #5094 from penpot/alotor-fix-plugins
🐛 Fix small problems in plugins
2024-09-17 12:37:43 +02:00
Denys Kisil
2b492134be 🌐 Add translations for: Ukrainian (ukr_UA).
Currently translated at 85.5% (1243 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
2024-09-17 12:09:20 +02:00
Eva Marco
a26deafa75 ♻️ Update the colors and icon of some toast notification 2024-09-17 12:08:17 +02:00
alonso.torres
cf705e352b 🐛 Fix small problems in plugins 2024-09-17 10:19:37 +02:00
Andrey Antukh
86c5ca4213 🐛 Fix incorrect redirect handling on request-access go-home button 2024-09-16 18:53:56 +02:00
Andrey Antukh
179d534237 🐛 Fix several issues related to invalid colors inserted on shadows 2024-09-16 18:32:40 +02:00
Andrey Antukh
162507264c 🐛 Reexecute file migration 26 again for shapes that has transform prop as nil 2024-09-16 18:32:40 +02:00
Andrey Antukh
7e0a8b6227 Merge pull request #5092 from penpot/palbs-fix-request-acces-dont-go-your-team
🐛 Fix request access to the Team don't go to Your Penpot team
2024-09-16 18:32:19 +02:00
Andrey Antukh
b50fcee079 Merge pull request #5090 from penpot/alotor-new-apis
Plugins - API's modifications
2024-09-16 18:29:51 +02:00
alonso.torres
9bca42c14a Fixed plugin registration props 2024-09-16 15:46:02 +02:00
Pablo Alba
475d14edf4 🐛 Fix request access to the Team don't go to Your Penpot team 2024-09-16 14:42:52 +02:00
alonso.torres
214733c880 ⬆️ Update plugins runtime 2024-09-16 09:48:56 +02:00
alonso.torres
979828ffe3 🐛 Fix issue when exporting libraries when merging libraries 2024-09-16 09:08:51 +02:00
alonso.torres
65bb795199 🐛 Fix visual problem with stroke cap menu 2024-09-16 09:07:57 +02:00
Henrik Allberg
7bdc97fbfa 🌐 Add translations for: Swedish.
Currently translated at 99.5% (1446 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/sv/
2024-09-13 23:09:19 +02:00
Alejandro
a0546b2e63 Merge pull request #5086 from penpot/niwinz-bugfix-1
🐛 Ignore object thumbnail requests if file is already marked as deleted
2024-09-13 12:30:27 +02:00
alonso.torres
d6f6d78b1e New viewport functions 2024-09-13 12:29:07 +02:00
alonso.torres
8c1fba5160 Add api methods to align, distribute and flatten shapes 2024-09-13 12:29:07 +02:00
alonso.torres
fb39dd5440 Methods for comments 2024-09-13 12:29:07 +02:00
alonso.torres
dd0c5b7806 Add support to guides for plugins 2024-09-13 11:30:59 +02:00
Andrey Antukh
9e94cf7b99 ♻️ Simplify internal implementation of sm/schema namespace 2024-09-13 11:30:55 +02:00
Andrey Antukh
b882b9e283 🔥 Remove usage of public usage of sm/define funcion 2024-09-13 11:30:55 +02:00
Andrey Antukh
cdcff62232 Store some profile props on browser global storage 2024-09-13 11:30:55 +02:00
Andrey Antukh
c8caca77a3 Add storage namespacing
Allows separate global properties from user specific properties
2024-09-13 11:30:55 +02:00
Andrey Antukh
f291125377 🐛 Add migration for invalid value on layout-wrap-type on shape prop 2024-09-12 21:33:01 +02:00
Andrey Antukh
0ce981a68c 🐛 Add missing ref-id unsassign on srepl helpers for process file 2024-09-12 21:32:34 +02:00
Andrey Antukh
a8814dcaba 🐛 Add missing fields on file-gc libraries fetching sql 2024-09-12 21:07:19 +02:00
Pablo Alba
229eeae6db 🐛 Fix bad redirect on new oops page with social login 2024-09-12 16:35:49 +02:00
Andrey Antukh
d03788af93 🐛 Ignore object thumbnail requests if file is already marked as deleted 2024-09-12 15:23:31 +02:00
Alejandro Alonso
017aad6454 🐛 Fix export failed error when exporting multiple shapes 2024-09-12 12:55:32 +02:00
Henrik Allberg
5059d71509 🌐 Add translations for: Swedish.
Currently translated at 99.5% (1446 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/sv/
2024-09-11 20:09:23 +00:00
Alejandro Alonso
042b3a71d8 Merge remote-tracking branch 'origin/staging' into develop 2024-09-11 12:46:04 +02:00
Alejandro Alonso
767ec37b83 Merge remote-tracking branch 'origin/main' into staging 2024-09-11 12:45:39 +02:00
Alejandro Alonso
89f64e0c49 🐛 Fix challenge redirect with parameters 2024-09-11 12:30:12 +02:00
Alejandro Alonso
eadae5e2cd Merge remote-tracking branch 'origin/staging' into develop 2024-09-11 12:05:45 +02:00
Alejandro Alonso
d108ad904e Merge remote-tracking branch 'origin/main' into staging 2024-09-11 12:05:21 +02:00
Alejandro Alonso
6564736d3e 🐛 Fix challenge redirect with parameters 2024-09-11 12:03:32 +02:00
Alejandro Alonso
7f9c4df284 Merge remote-tracking branch 'origin/staging' into develop 2024-09-11 11:34:35 +02:00
Alejandro Alonso
d01cd70c6b Merge remote-tracking branch 'origin/main' into staging 2024-09-11 11:34:04 +02:00
Alejandro
ea7768117c Merge pull request #5082 from penpot/superalex-fix-challenge-redirect-with-parameters
🐛 Fix challenge redirect with parameters
2024-09-11 11:33:45 +02:00
Alejandro Alonso
5bfb39cdf6 🐛 Fix challenge redirect with parameters 2024-09-11 11:23:19 +02:00
Henrik Allberg
76c054a591 🌐 Add translations for: Swedish.
Currently translated at 60.9% (885 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/sv/
2024-09-10 19:09:36 +00:00
Jarne Förster
4471dca3f3 🌐 Add translations for: German.
Currently translated at 98.0% (1424 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-09-10 19:09:11 +00:00
Pablo Alba
29f1c2bdad Merge pull request #5080 from penpot/niwinz-oidc-fix-limits-issues
🐛 Fix oidc auth internal limits issue
2024-09-10 16:41:44 +02:00
Andrey Antukh
e79f9ba40f 🐛 Increase token limit 2024-09-10 12:39:54 +02:00
Andrey Antukh
452aabdec6 🐛 Don't send user props on auth token after oidc login 2024-09-10 12:39:54 +02:00
Denys Kisil
6c3b82ed85 🌐 Add translations for: Ukrainian (ukr_UA).
Currently translated at 85.6% (1244 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
2024-09-09 20:32:26 +02:00
Madalena Melo
f91434433e 🌐 Added translation for: Swedish. 2024-09-09 16:10:57 +02:00
Madalena Melo
b6f82be56a 🌐 Added translation for: Portuguese. 2024-09-09 16:10:46 +02:00
Alejandro Alonso
9e3f8e7827 Merge remote-tracking branch 'origin/staging' into develop 2024-09-09 11:09:53 +02:00
Eva Marco
3a4e9ccc5a 👷 Fix CI error 2024-09-09 10:32:50 +02:00
Aitor Moreno
860e32d965 Merge pull request #5070 from penpot/superalex-fix-onboarding
🐛 Fix onboarding questions
2024-09-09 10:19:03 +02:00
Andrey Antukh
495f9dfa84 Merge pull request #5064 from penpot/superalex-release-notes-2.2
 Release notes for 2.2
2024-09-09 09:54:50 +02:00
Alejandro
133ca33cb5 Merge pull request #5076 from penpot/niwinz-exporter-config-parse
🐛 Fix issues on parsing configuration on exporter
2024-09-09 09:54:12 +02:00
Andrey Antukh
1c69a9fd8a 🐛 Fix config parsing on exporter 2024-09-09 09:47:55 +02:00
Andrey Antukh
15faa57e01 🐛 Fix decoding on sm/set schema 2024-09-09 09:46:50 +02:00
Alejandro
f5510234cf Merge pull request #5066 from penpot/eva-fix-frame-row-menu
🐛 Fix guides submenu visualization
2024-09-09 06:49:05 +02:00
Denys Kisil
c633970f9d 🌐 Add translations for: Ukrainian (ukr_UA).
Currently translated at 78.5% (1141 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
2024-09-08 14:09:15 +02:00
Denys Kisil
95e5b1ec5e 🌐 Add translations for: Ukrainian (ukr_UA).
Currently translated at 55.3% (804 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
2024-09-07 10:46:03 +02:00
Belén Albeza
eb720b053a Merge pull request #5057 from penpot/eva-fix-css-compilation
🔧 Rearrange css files for compilation
2024-09-06 14:45:52 +02:00
Alejandro Alonso
efc61241a0 Merge remote-tracking branch 'origin/staging' into develop 2024-09-06 13:50:37 +02:00
Alejandro Alonso
5b0331611d Merge remote-tracking branch 'origin/main' into staging 2024-09-06 13:50:09 +02:00
Alejandro
f8f1c58f61 Merge pull request #5069 from penpot/niwinz-storybook-build-fix
🐛 Fix storybook build related to commonjs to esm module conversion issue
2024-09-06 13:43:04 +02:00
Andrey Antukh
3f34aa92fa Add support for optional human challenge 2024-09-06 13:39:53 +02:00
Alejandro Alonso
c99102e49b 🐛 Fix onboarding questions 2024-09-06 13:18:39 +02:00
Andrey Antukh
d583661e58 🐛 Fix storybook build related to commonjs to esm module conversion issue 2024-09-06 12:31:48 +02:00
Andrey Antukh
cfad1d178f Merge pull request #5068 from penpot/alotor-plugins-install-profile
 Change installation data to profile
2024-09-06 12:05:52 +02:00
Andrey Antukh
ffa326e08f Merge pull request #5067 from penpot/alotor-fix-validation
🐛 Fix problem when dismissing shared library update
2024-09-06 11:31:22 +02:00
alonso.torres
c24b2dadec Change installation data to profile 2024-09-06 11:10:32 +02:00
alonso.torres
03040ed40b 🐛 Fix problem when dismissing shared library update 2024-09-06 11:02:02 +02:00
Alejandro Alonso
5e89cd1cb3 Release notes for 2.2 2024-09-06 10:49:20 +02:00
Eva Marco
bf202473e9 🐛 Fix guides submenu visualization 2024-09-06 09:47:09 +02:00
Andrey Antukh
9a3b5337d7 Merge pull request #5062 from penpot/alotor-plugins-fix-interactions
🐛 Fix plugins add interaction
2024-09-05 16:22:46 +02:00
alonso.torres
396cbb27b2 🐛 Fix plugins add interaction 2024-09-05 16:00:04 +02:00
Alejandro
b4e6f8bc73 Merge pull request #5061 from penpot/niwinz-challenge
 Add support for optional human challenge
2024-09-05 15:49:50 +02:00
Andrey Antukh
d88f28f5c2 Add support for optional human challenge 2024-09-05 15:35:39 +02:00
Andrey Antukh
886c0c596f Merge pull request #5060 from penpot/alotor-bugfixes
Bugfixes
2024-09-05 15:32:44 +02:00
alonso.torres
b15b394c65 🐛 Fix problem when creating a component instance from grid layout 2024-09-05 15:11:04 +02:00
Eva Marco
e36cf1d963 🐛 Fix onboarding slide after rearrange 2024-09-05 14:46:49 +02:00
alonso.torres
caf78a6b4d 🐛 Fix layer panel overflowing 2024-09-05 11:50:16 +02:00
alonso.torres
6a161267ba 🐛 Fix problem with overlay positions in viewer 2024-09-05 10:48:00 +02:00
Eva Marco
a0bb5e5ef3 ♻️ Remove unnecesary code 2024-09-05 09:41:11 +02:00
Eva Marco
34cc211912 🔧 Rearrange css files for compilation 2024-09-05 09:39:43 +02:00
Eva Marco
e95713c1df 🐛 Fix visual integration test 2024-09-05 09:39:43 +02:00
Alejandro Alonso
e189dc965d Merge remote-tracking branch 'origin/staging' into develop 2024-09-05 09:37:16 +02:00
alonso.torres
a180c33a32 🐛 Fix problem with SVG import 2024-09-05 09:26:22 +02:00
Alejandro
ea8febdb7d Merge pull request #5056 from penpot/niwinz-refactor-recent-colors
♻️ Refactor recent colors and local storage abstraction
2024-09-05 09:07:26 +02:00
Alejandro
f765cc8dbc Merge pull request #5011 from penpot/palba-testab-start-workspace
A/B test start directly at the workspace
2024-09-05 07:05:57 +02:00
Pablo Alba
81b7972347 🎉 Test A/B for start in workspace 2024-09-04 17:19:39 +02:00
Andrey Antukh
1281670c61 Clear storage on user logout 2024-09-04 16:20:00 +02:00
Andrey Antukh
b8c6103858 Add performance enhancements for util/storage abstraction layer 2024-09-04 16:20:00 +02:00
Andrey Antukh
b2c0bed84c Add efficiency improvements to use-resize-hook 2024-09-04 16:20:00 +02:00
Andrey Antukh
9619fcbc1f Make efficiency improvements to use-shared-state hook 2024-09-04 16:20:00 +02:00
Andrey Antukh
e9c55e9eb4 Make recent colors to be stored locally instead of on file 2024-09-04 16:20:00 +02:00
Belén Albeza
53f580ad40 Merge pull request #5017 from penpot/eva-add-select-to-ds
 Add select component to the DS
2024-09-04 15:51:10 +02:00
Andrey Antukh
cf0045681e Merge pull request #5054 from penpot/alotor-plugins-fixes
Update API types
2024-09-04 14:16:01 +02:00
Andrey Antukh
488d034a58 Merge pull request #5055 from penpot/eva-fix-webhook-checkbox
🐛  Fix webhook checkbox position
2024-09-04 14:15:37 +02:00
alonso.torres
762a883b39 🐛 Fix problem with font weight and style 2024-09-04 13:52:48 +02:00
alonso.torres
a63ded1ba1 Change type names in plugins 2024-09-04 13:29:56 +02:00
Eva Marco
8d66275187 🐛 Fix webhook checkbox position 2024-09-04 12:51:30 +02:00
alonso.torres
f812b28892 ⬆️ Update plugin dependencies 2024-09-04 12:38:50 +02:00
Alejandro
59063e861c Merge pull request #5053 from penpot/niwinz-update-file-refactor
♻️ Refactor file-update for make it more reusable
2024-09-04 12:30:36 +02:00
Andrey Antukh
873c9b1903 Merge pull request #5050 from penpot/hiru-ordered-maps
🔧 Add serializable ordered collections
2024-09-04 12:26:21 +02:00
Andrey Antukh
9da891e9b0 📎 Enable auto-file-snapshot feature scripts/repl 2024-09-04 12:18:31 +02:00
Andrey Antukh
a6de12323e ♻️ Refactor file-update for make it more reusable 2024-09-04 12:18:31 +02:00
Stas Haas
f84b3187a5 🌐 Add translations for: German.
Currently translated at 97.7% (1421 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-09-04 12:09:13 +02:00
Unreal Vision
087f779fef 🌐 Add translations for: French.
Currently translated at 96.3% (1400 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fr/
2024-09-04 12:09:12 +02:00
Alejandro Alonso
edeb16bc26 Merge remote-tracking branch 'origin/staging' into develop 2024-09-04 12:02:31 +02:00
Alejandro Alonso
52d099c80e Merge remote-tracking branch 'origin/main' into staging 2024-09-04 12:02:04 +02:00
Alejandro
b2010e5fd8 Merge pull request #5052 from penpot/niwinz-bugfix-srepl-helpers
🐛 Fix issues with srepl helper for profile deletion in bulk
2024-09-04 12:01:55 +02:00
Alejandro
5808bd3743 Merge pull request #5045 from penpot/niwinz-fix-file-gc
🐛 Fix issues on file-gc task
2024-09-04 11:11:13 +02:00
Andrey Antukh
d5f5c440dd 🐛 Fix issues with srepl helper for profile deletion in bulk 2024-09-04 11:09:05 +02:00
Alejandro Alonso
90d947391a Merge remote-tracking branch 'origin/staging' into develop 2024-09-04 08:59:05 +02:00
Alejandro Alonso
729f679c0f Merge remote-tracking branch 'origin/main' into staging 2024-09-04 08:58:51 +02:00
Alejandro
9f52709a42 Merge pull request #5047 from penpot/niwinz-hotfix-webhooks
🐛 Fix incorrect params handling on webhook processing task
2024-09-04 08:57:53 +02:00
Andrés Moya
47cc80a93f 🔧 Add serializable ordered collections 2024-09-03 23:35:53 +02:00
Andrey Antukh
85444f5a47 🐛 Fix incorrect params handling on webhook processing task 2024-09-03 17:19:35 +02:00
Andrey Antukh
50df2279a7 🐛 Make the media cleaning on file-gc task aware of snapshots
It now takes in account the snapshots, and prevents
deletion of media files used in snapshots.
2024-09-03 14:50:17 +02:00
Andrey Antukh
71ba0242c7 🐛 Add missing type decoding on changes schema 2024-09-03 14:42:00 +02:00
Andrey Antukh
1f8cfde1cf Merge pull request #5046 from penpot/alotor-plugins-fixes
Plugins small fixes
2024-09-03 14:36:59 +02:00
Alejandro Alonso
5f2ec595cb 📎 Update changelog 2024-09-03 13:15:48 +02:00
alonso.torres
37a6446e32 🐛 Fix problem with font style 2024-09-03 13:10:28 +02:00
alonso.torres
be84b1cb01 🐛 Change place for circular dependency workaround 2024-09-03 13:10:28 +02:00
Alejandro Alonso
9fb91b3052 Merge remote-tracking branch 'origin/staging' into develop 2024-09-03 13:06:40 +02:00
Alejandro Alonso
689aab32c9 📎 Update changelog 2024-09-03 13:04:04 +02:00
Alejandro Alonso
c642f4afa2 📎 Update version.txt file 2024-09-03 12:52:36 +02:00
Alejandro
a62a083294 Merge pull request #5038 from penpot/palba-add-export-event
🎉 Add export event for telemetry
2024-09-03 12:51:06 +02:00
Pablo Alba
2a13c2ec00 🎉 Add export event for telemetry 2024-09-03 12:03:36 +02:00
Eva Marco
f3525b9ff2 Merge pull request #5044 from penpot/ladybenko-update-changes-ds
📚 Update changelog with the latest DS features
2024-09-03 10:53:00 +02:00
Belén Albeza
d2509f4b97 📚 Update changelog with the latest DS features 2024-09-03 10:38:40 +02:00
Andrey Antukh
6d8c424710 📎 Fix linter issues on ui.auth ns 2024-09-03 10:38:10 +02:00
Andrey Antukh
93e8657f73 Merge remote-tracking branch 'origin/staging' into develop 2024-09-03 08:02:57 +02:00
Alejandro Alonso
91f6c001c0 📚 Update changelog 2024-09-03 06:47:53 +02:00
Andrey Antukh
0dd8300a80 Merge pull request #5037 from penpot/ladybenko-8615-ds-translations
Enable translations for the DS / Storybook
2024-09-02 19:45:09 +02:00
Eva Marco
298db46722 Add documentation to select on storybook 2024-09-02 16:56:53 +02:00
Alejandro
c2b97b13a1 Merge pull request #5042 from penpot/niwinz-update-changelog
📚 Update changelog
2024-09-02 15:22:27 +02:00
Belén Albeza
8feb5dabb0 Use translations in a DS component story 2024-09-02 14:51:41 +02:00
Belén Albeza
8aaa04b1f8 Add English translations to storybook template 2024-09-02 14:51:41 +02:00
Andrey Antukh
a28117b301 📚 Add missing backend enhancements on the changelog 2024-09-02 13:21:02 +02:00
Andrey Antukh
0117a4767d 📎 Rename file-snapshot to auto-file-snapshot 2024-09-02 11:52:19 +02:00
Eva Marco
0c6b0598fa Add new select ds component to storybook 2024-08-29 14:14:12 +02:00
Eva Marco
f2a2d772b0 Add new select component to the ds 2024-08-29 14:14:08 +02:00
Andrey Antukh
bf60bf1848 Merge pull request #5033 from penpot/superalex-revert-test-default-theme
Revert "🎉 Test A/B for starting with light theme"
2024-08-29 11:42:04 +02:00
Andrey Antukh
c581395df2 Merge pull request #5034 from penpot/superalex-track-copy-shared-link-event
 Track copy shared link event
2024-08-29 10:26:34 +02:00
Alejandro Alonso
8a44fb689a 🐛 Fix create share link name 2024-08-29 10:25:08 +02:00
Alejandro Alonso
9fd36526ef Track copy shared link event 2024-08-29 10:25:08 +02:00
Alejandro Alonso
78f4d9cc5d 🎉 Revert test A/B for starting with light theme
This reverts commit b0af94415f.
2024-08-28 13:00:43 +02:00
Alejandro
bd2a3e197a Merge pull request #5032 from penpot/niwinz-backports-1
🐛 Backport several bugfixes from develop
2024-08-28 12:49:16 +02:00
Alejandro
d703205921 Merge pull request #5028 from penpot/niwinz-path-changes
🐛 Add missing safechecks and schema validations
2024-08-28 12:41:18 +02:00
Alejandro
1e73bec2b9 Merge pull request #5031 from penpot/niwinz-fire-version-txt
🔥 Remove the usage of version.txt
2024-08-28 12:30:57 +02:00
Andrey Antukh
1abbeb0273 Merge pull request #5015 from penpot/yamila-moreno-patch-1
Update manage.sh
2024-08-28 11:15:07 +02:00
Andrey Antukh
d25424d325 🔥 Remove the usage of version.txt 2024-08-28 11:14:28 +02:00
Andrey Antukh
cc98ac5853 🐛 Fix json encoding on zip encoding decoding 2024-08-28 10:43:47 +02:00
Andrey Antukh
05750c3b38 🐛 Add schema validation for color changes 2024-08-28 10:43:47 +02:00
Andrey Antukh
3ddecef5a7 Ensure plain map on path params in several functions 2024-08-28 10:31:22 +02:00
Andrey Antukh
7fd96a0533 🎉 Backport app.common.json namespace from develop 2024-08-28 10:30:11 +02:00
Andrey Antukh
19d6f4381a Merge pull request #5023 from penpot/eva-add-tooltips-to-typography
🐛 Add missing tooltips to typography options
2024-08-27 17:54:41 +02:00
Andrey Antukh
25e9129a8e 🔥 Remove unused and deprecated helpers from app.util.object ns 2024-08-27 16:44:14 +02:00
Andrey Antukh
569674452a Add label and id support for debug snapshot helpers 2024-08-27 15:43:31 +02:00
Andrey Antukh
2643dae0a7 🐛 Fix json encoding on zip encoding decoding 2024-08-27 15:43:31 +02:00
Andrey Antukh
1f53e48032 🐛 Add schema validation for color changes 2024-08-27 10:48:38 +02:00
Andrey Antukh
ef3a47b492 Add efficiency changes to get-segments helper 2024-08-27 10:48:38 +02:00
Andrey Antukh
f302c724c4 Add efficiency changes on make-curve-point helper 2024-08-27 10:48:37 +02:00
Andrey Antukh
4ce654511b Ensure plain map on path params in several functions 2024-08-27 10:48:37 +02:00
Andrey Antukh
2f68310a7c 📎 Add some fixmes for future path changes 2024-08-27 10:48:37 +02:00
Alejandro
67cd855e97 Merge pull request #5027 from penpot/niwinz-backend-improvements
 Add efficiency improvements to xlog task
2024-08-27 09:59:59 +02:00
Andrey Antukh
ceaafdbb1c Add offload mechanism for file snapshots 2024-08-26 13:52:42 +02:00
Oğuz Ersen
ca283c2d26 🌐 Add translations for: Turkish.
Currently translated at 99.5% (1447 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/tr/
2024-08-26 13:09:24 +02:00
Andrey Antukh
8dea5d5158 ♻️ Make file-xlog-gc task more scalable 2024-08-26 11:15:59 +02:00
Alejandro
7ea5c79393 Merge pull request #5019 from penpot/niwinz-static-error-duplication
 Add improvements on how UI (React) errors are handled
2024-08-26 09:26:28 +02:00
Stephan Paternotte
9008eb218b 🌐 Add translations for: Dutch.
Currently translated at 99.5% (1447 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/nl/
2024-08-24 17:09:57 +02:00
Yaron Shahrabani
089b77379d 🌐 Add translations for: Hebrew.
Currently translated at 99.5% (1446 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
2024-08-24 17:09:56 +02:00
Andrey Antukh
215148ca81 Add better fillfactor setting for storage_object and task tables 2024-08-23 15:09:58 +02:00
Eva Marco
897960194e 🐛 Add missing tooltips to typography options 2024-08-23 13:42:33 +02:00
Alejandro
5d97f4b924 Merge pull request #5020 from penpot/eva-fix-color-picker
🐛  Fix color picker
2024-08-23 12:37:25 +02:00
Alejandro
e7b663749a Merge pull request #5021 from penpot/eva-fix-design-tab-layout
🐛 Fix design tab layout after new tab component added
2024-08-23 12:25:38 +02:00
Eva Marco
aa5999b2e0 🐛 Fix design tab layout after new tab component added 2024-08-23 11:59:23 +02:00
Alejandro
736d75a93c Merge pull request #5009 from penpot/niwinz-json-decoder-2
🎉 Add `:assign` operation as alternative to `:set`
2024-08-23 11:53:07 +02:00
Eva Marco
c81a17ada5 🐛 Fix color picker 2024-08-23 11:52:05 +02:00
Andrey Antukh
401a28f317 ⬆️ Update rumext to v2.14
Adds some improvements on compiler
2024-08-23 11:21:54 +02:00
Andrey Antukh
f16caa2b98 💄 Add cosmetic changes on sidebar/options ns 2024-08-23 11:21:54 +02:00
Andrey Antukh
868af29d14 💄 Add some cosmetic changes to sidebar ns 2024-08-23 11:21:54 +02:00
Andrey Antukh
a091c9c910 ♻️ Refactor how UI error reporting is handled 2024-08-23 11:21:54 +02:00
Anonymous
1d1d4d9371 🌐 Add translations for: Serbian.
Currently translated at 96.0% (1395 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/sr/
2024-08-23 11:16:13 +02:00
Anonymous
d578659b21 🌐 Add translations for: Dutch.
Currently translated at 96.2% (1399 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/nl/
2024-08-23 11:16:13 +02:00
Anonymous
2be9cebb0e 🌐 Add translations for: Portuguese (Portugal).
Currently translated at 96.2% (1399 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/pt_PT/
2024-08-23 11:16:13 +02:00
Anonymous
982b900066 🌐 Add translations for: Hebrew.
Currently translated at 96.2% (1399 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
2024-08-23 11:16:12 +02:00
Anonymous
4c1bc7c3c1 🌐 Add translations for: German.
Currently translated at 96.2% (1399 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-08-23 11:16:12 +02:00
Anonymous
fb09959459 🌐 Add translations for: Turkish.
Currently translated at 96.2% (1399 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/tr/
2024-08-23 11:16:12 +02:00
Anonymous
5601ed7071 🌐 Add translations for: Russian.
Currently translated at 96.1% (1397 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ru/
2024-08-23 11:16:12 +02:00
Anonymous
5ab282c344 🌐 Add translations for: French.
Currently translated at 96.2% (1398 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fr/
2024-08-23 11:16:12 +02:00
Anonymous
5eb4b28834 🌐 Add translations for: Spanish.
Currently translated at 99.1% (1440 of 1453 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/es/
2024-08-23 11:16:11 +02:00
Andrey Antukh
4cdea36b7c 📎 Rehash & sort all translations 2024-08-23 11:09:45 +02:00
Andrey Antukh
f2c1d4d83d Merge branch 'translations' into develop 2024-08-23 11:04:10 +02:00
Andrey Antukh
9dd0cd57ce Merge remote-tracking branch 'weblate/develop' into translations 2024-08-23 11:03:39 +02:00
Andrey Antukh
3026bd8aaf Merge remote-tracking branch 'origin/staging' into develop 2024-08-23 10:59:14 +02:00
Andrey Antukh
2ec27de353 🎉 Add :assing operation as altenative to :set 2024-08-23 10:55:10 +02:00
Andrey Antukh
f73e5446ab Merge pull request #5016 from penpot/superalex-bug-render-texts-without-position-data
🐛 Fix render of some texts without position data
2024-08-22 15:43:50 +02:00
Alejandro Alonso
df255b5a6f 🐛 Fix render of some texts without position data 2024-08-22 15:24:13 +02:00
Andrey Antukh
9a3c953f0f Merge pull request #5014 from penpot/juanfran-update-plugins-runtime
⬆️ Update plugins runtime
2024-08-22 12:47:02 +02:00
Yamila Moreno
02c031a0ef 📎 Delete unnecessary option in manage.sh script
Delete `-x` option as it gives an annoying output when we're not debugging.
2024-08-22 12:45:18 +02:00
Juanfran
a5114369ba ⬆️ Update plugins runtime 2024-08-22 12:13:20 +02:00
Andrey Antukh
4765685440 Merge pull request #5010 from penpot/eva-replace-tabs-component
♻️ Replace tabs component
2024-08-22 10:31:22 +02:00
Eva Marco
3f3c3a3df4 🐛 Fix labelled by on tab-panel component 2024-08-21 13:39:16 +02:00
Alejandro
baa52d432f Merge pull request #5003 from penpot/niwinz-json-decoder
🎉 Add json encode/decode mechanism for schemas
2024-08-21 12:48:41 +02:00
Andrey Antukh
89562d0231 Add schema validation for tabs 2024-08-21 11:55:12 +02:00
Eva Marco
3df9c88bb7 ♻️ Replace layer tabs component with the new tab switcher component 2024-08-21 11:54:39 +02:00
Andrey Antukh
cacee40d11 🎉 Add proper schema encoding/decoding mechanism
this allows almost all api operations to success usin application/json
encoding with the exception of the update-file, which we need to
approach a bit differently;

the reason update-file is different, is because the operations vector
is right now defined without the context of shape type, so we are just
unable to properly parse the value to correct type using the schema
decoding mechanism
2024-08-21 11:27:36 +02:00
Eva Marco
1782837a38 ♻️ Replace colorpicker modal tab component 2024-08-20 14:01:29 +02:00
Alejandro
de05521b57 Merge pull request #5001 from penpot/superalex-fix-deleted-fonts
🐛 Fix deleted fonts on file load
2024-08-20 13:13:48 +02:00
Alejandro Alonso
c86afca1d0 🐛 Fix deleted fonts on file load 2024-08-20 13:00:18 +02:00
Andrey Antukh
5617ca24b8 Merge pull request #5008 from penpot/superalex-improve-disabled-registry-flows
 Improve disabled registry flows
2024-08-20 10:11:20 +02:00
Eva Marco
c0cd980f5f ♻️ Replace libraries modal tab component 2024-08-20 09:55:18 +02:00
Alejandro Alonso
cd51f2f652 Improve disabled registry flows 2024-08-20 08:20:46 +02:00
Eva Marco
2f99d17885 ♻️ Replace tab switcher on design tab 2024-08-19 16:26:17 +02:00
Eva Marco
63ffa704f5 ♻️ Replace tab switcher on viewer 2024-08-19 16:26:10 +02:00
Eva Marco
129b7afda9 ♻️ Remove components preview 2024-08-19 16:25:46 +02:00
Pablo Alba
00bb988ecc Merge pull request #5007 from penpot/superalex-a-b-remove-testing-signup-01
 Add a/b remove testing for signup image
2024-08-19 10:49:32 +02:00
Alejandro Alonso
5efc56eb5a Revert " Add a/b testing for signup image"
This reverts commit 5ac6f04857.
2024-08-19 10:22:01 +02:00
Alejandro
0ccae600bc Merge pull request #5000 from penpot/palba-default-light
🎉 Test A/B for starting with light theme
2024-08-19 08:57:10 +02:00
Pablo Alba
b0af94415f 🎉 Test A/B for starting with light theme 2024-08-19 08:20:31 +02:00
Црнобог
1c09670e3c 🌐 Add translations for: Serbian.
Currently translated at 98.6% (1389 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/sr/
2024-08-17 13:09:32 +02:00
Andrey Antukh
0db1eed87f Improve word-string schema generator
make it to generate a more readable strings
2024-08-16 14:43:06 +02:00
Andrey Antukh
db52d98595 📎 Update user ns on common and backend 2024-08-16 14:43:06 +02:00
Andrey Antukh
e46b5b3f57 🎉 Add json module to common 2024-08-16 14:43:06 +02:00
Alejandro
d1d3b4353a Merge pull request #4987 from penpot/eva-add-selection-colors-to-ds
  Add selection colors to ds
2024-08-16 07:59:18 +02:00
Црнобог
3c0944ebfc 🌐 Add translations for: Serbian.
Currently translated at 98.5% (1388 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/sr/
2024-08-15 17:09:28 +02:00
Црнобог
a2725ed8fe 🌐 Add translations for: Russian.
Currently translated at 99.6% (1403 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ru/
2024-08-15 17:09:18 +02:00
Alejandro
84bfef9938 Merge pull request #4920 from penpot/palba-request-access
Oops page and Request access
2024-08-14 15:53:45 +02:00
Pablo Alba
6169f5c2e8 🎉 New oops page with login and request access 2024-08-14 15:32:04 +02:00
Andrey Antukh
fc14871d01 Merge pull request #4993 from penpot/eva-fix-fill-menu
🐛 Fix collapsing fill menu
2024-08-14 13:09:03 +02:00
Andrey Antukh
bcfa1d4394 Merge pull request #4996 from penpot/eltociear-patch-2
🐛 Update time.cljc
2024-08-14 13:08:40 +02:00
Ikko Eltociear Ashimine
2361b2b63a 🐛 Update time.cljc
prefered -> preferred
2024-08-14 12:58:44 +02:00
Andrey Antukh
380ead2ad6 Merge pull request #4994 from penpot/superalex-make-explicit-test-openldap-devenv-docker-ulimits
 Make explicit test-openldap devenv docker ulimits
2024-08-14 12:57:09 +02:00
Alejandro Alonso
3df45d697d Make explicit test-openldap devenv docker ulimits 2024-08-14 11:07:00 +02:00
Alejandro
efb70f0b97 Merge pull request #4985 from penpot/niwinz-hotfix-2
🐛 Disable ipv6 from docker nginx resolver.
2024-08-14 10:50:26 +02:00
Alejandro
d9a941cb32 Merge pull request #4992 from penpot/juanfran-invalid-content-path-arguments
🐛 Fix typo in command parsing (paras to params)
2024-08-14 09:40:37 +02:00
Eva Marco
f43ca1869b 🐛 Fix collapsing fill menu 2024-08-14 09:24:26 +02:00
Juanfran
a34b06cfb4 🐛 Fix typo in command parsing (paras to params)
Signed-off-by: Juanfran <juanfran.ag@gmail.com>
2024-08-14 09:23:23 +02:00
Madalena Melo
f5b910d391 🌐 Added translation for: Serbian. 2024-08-14 09:06:16 +02:00
Alejandro
924c1d60f9 Merge pull request #4990 from penpot/niwinz-hotfix-5
🐛 Update storage specs
2024-08-13 12:47:24 +02:00
Andrey Antukh
6b80f19e5f 🐛 Update storage specs 2024-08-13 12:21:16 +02:00
Eva Marco
b57e68f4b6 Add selection colors to ds 2024-08-13 12:06:46 +02:00
Alejandro
000d2c3935 Merge pull request #4989 from penpot/niwinz-hotfix-3
🐛 Backport  storage changes from develop
2024-08-13 11:26:49 +02:00
Alejandro
d2311f066a Merge pull request #4988 from penpot/niwinz-fix-notifications
🐛 Fix incorrect params for notifications
2024-08-13 11:17:58 +02:00
Andrey Antukh
91435bf372 🐛 Backport storage backend naming changes from develop
for properly handle backward comaptibility when two
versions are running over a single database
2024-08-13 11:14:38 +02:00
Andrey Antukh
aa39de4ea8 🐛 Fix incorrect params for notifications 2024-08-13 11:04:26 +02:00
Eva Marco
215f6fc0ab Merge pull request #4973 from penpot/ladybenko-8255-focus-mode
🐛 Fix layer sidebar in focus mode for long names
2024-08-13 10:34:41 +02:00
Alejandro
ea5c22c244 Merge pull request #4983 from penpot/niwinz-backports-1
🐛 Backport bugfixes from develop
2024-08-13 08:25:10 +02:00
Belén Albeza
fc333ae098 Merge pull request #4941 from penpot/eva-tabs-component-ds
  Add tabs component to DS
2024-08-12 17:46:59 +02:00
Belén Albeza
d3e891eec3 Enable focusing on tab-switcher* panel 2024-08-12 17:35:28 +02:00
Eva Marco
66d30e35c7 Add tab switcher component documentation 2024-08-12 17:35:28 +02:00
Eva Marco
b8693c3f85 Add tab component to the DS 2024-08-12 17:35:26 +02:00
Eva Marco
4b2742efca Merge pull request #4972 from penpot/ladybenko-7887-toast
Implement `toast*` component
2024-08-12 16:28:57 +02:00
Andrey Antukh
e07c1bba7a 🐛 Disable ipv6 from docker nginx resolver 2024-08-12 16:22:19 +02:00
Andrey Antukh
ec56a4149b 🐛 Fix unhandled exception on try to reuse registration token 2024-08-12 12:59:18 +02:00
Andrey Antukh
314742a563 Add :params prop to :not-found exception 2024-08-12 12:59:18 +02:00
Andrey Antukh
38c9e3e7cc 🐛 Fix error handling issue on login with oidc
happens when no oidc backend is configured on backend
2024-08-12 12:59:18 +02:00
Andrey Antukh
c1435fba95 Merge pull request #4980 from rasom/fix-link-contributing-guide
📚 Fix dead link in contributing guide
2024-08-12 12:25:23 +02:00
Alejandro
b13148265e Merge pull request #4982 from penpot/niwinz-bugfix-3
🐛 Bugfixes
2024-08-12 12:12:15 +02:00
Andrey Antukh
c0174ab501 🐛 Fix unhandled exception on try to reuse registration token 2024-08-12 11:55:19 +02:00
Andrey Antukh
77c45ed109 Add better error reporting on offload-file-data task 2024-08-12 11:55:19 +02:00
Andrey Antukh
7df68bb8bd Add :params prop to :not-found exception 2024-08-12 11:55:19 +02:00
Andrey Antukh
ab461ba560 🐛 Launch offload only if file-gc has processed the file 2024-08-12 11:55:19 +02:00
Alejandro
280252d40e Merge pull request #4958 from penpot/niwinz-fdata-storage-offload
🎉 Add file-data offload mechanism
2024-08-12 10:59:29 +02:00
Alhassan Atama
09b6989491 🌐 Add translations for: Igbo.
Currently translated at 37.1% (523 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ig/
2024-08-11 20:09:13 +00:00
Alhassan Atama
f96bbb38b0 🌐 Add translations for: Hausa.
Currently translated at 89.9% (1267 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ha/
2024-08-11 20:09:13 +00:00
Roman Volosovskyi
f0e3dc2f0e 📚 Fix dead link in contributing guide 2024-08-11 22:03:41 +02:00
Andrey Antukh
d2937a76d9 🐛 Fix error handling issue on login with oidc
happens when no oidc backend is configured on backend
2024-08-09 14:28:18 +02:00
Andrey Antukh
3219c150d4 Add better internal fillfactor setting for file table
Increasing the change for HOT updates on db for this heavy-update
table
2024-08-09 14:28:18 +02:00
Andrey Antukh
ba167f256b Add performance enhancements on telemetry related queries 2024-08-09 14:28:18 +02:00
Andrey Antukh
0e92bcc0de 🎉 Add file-data offload mechanism 2024-08-09 14:28:18 +02:00
Andrey Antukh
f6bfe3931c Add performance enhacements to storage/gc-touched task 2024-08-09 14:13:33 +02:00
Andrey Antukh
253b9e5bd8 Split file-gc task in two separated tasks
Add a new file-gc-scheduler task for analizing all files for
elegibility and leave file-gc task with the responsability to
performn the GC operation.
2024-08-09 14:13:33 +02:00
Belén Albeza
604f80de20 📚 Add documentation for toast* 2024-08-09 13:07:55 +02:00
Belén Albeza
0aa8f7bfc6 🐛 Fix layer sidebar in focus mode for long names 2024-08-09 12:54:42 +02:00
Dário
4cc2c736e9 🌐 Add translations for: Portuguese (Portugal).
Currently translated at 100.0% (1408 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/pt_PT/
2024-08-09 04:09:16 +02:00
Belén Albeza
9455b56c07 Implement toast* component 2024-08-08 15:46:57 +02:00
Andrey Antukh
d6f528acd2 Merge pull request #4955 from penpot/eva-bugfixing-1
🐛 Fix several bugs
2024-08-08 11:38:18 +02:00
Alejandro Alonso
9344fb958a Merge remote-tracking branch 'origin/staging' into develop 2024-08-08 07:43:10 +02:00
Andrey Antukh
2533d0ebc0 Add naming consistency changes for file_data_fragment table 2024-08-08 07:42:17 +02:00
Alejandro
6ee9025f13 Merge pull request #4971 from penpot/niwinz-fdata-storage-offload-2
 Add naming consistency changes for file_data_fragment table
2024-08-08 07:41:54 +02:00
Alejandro
3a2e868d80 Merge pull request #4915 from penpot/niwinz-mini-refactor-notifications
♻️ Mini refactor of notification components locations
2024-08-08 07:18:13 +02:00
Andrey Antukh
86a732600b Add naming consistency changes for file_data_fragment table 2024-08-07 16:34:39 +02:00
Andrey Antukh
22f3dba842 💄 Update run-store helper 2024-08-07 16:07:59 +02:00
Andrey Antukh
bde1cd3f5f 🐛 Fix unexpected exception on frontend test
caused by unexpected return nil on a merge-map
2024-08-07 16:07:59 +02:00
Andrey Antukh
f187012469 ♻️ Refactor naming and location of flash notifications 2024-08-07 15:04:52 +02:00
Belén Albeza
3917215952 Merge pull request #4969 from penpot/superalex-fix-storybook-css-path
🐛 Fix storybook css path
2024-08-07 09:31:00 +02:00
Alejandro Alonso
5f0c036ad5 🐛 Fix storybook css path 2024-08-07 06:46:06 +02:00
Andrey Antukh
f0342f25ea Merge pull request #4967 from penpot/superalex-fix-missing-env-variable-for-building
🐛 Fix missing storybook env variable for building
2024-08-06 17:32:22 +02:00
Alejandro Alonso
f5a8c806d9 🐛 Fix missing storybook env variable for building 2024-08-06 16:34:09 +02:00
Alejandro
f8cbe1dfbf Merge pull request #4965 from penpot/niwinz-storybook-fixes
⬆️ Update beicon version to v2.2
2024-08-06 12:52:58 +02:00
Andrey Antukh
c6c9e7d179 ⬆️ Update beicon version to v2.2
Fixes the esm build compatibility issues
2024-08-06 12:29:18 +02:00
Andrey Antukh
36ac81bb43 Merge pull request #4964 from penpot/superalex-fix-storybook-build
🐛 Fix storybook build
2024-08-06 10:47:54 +02:00
Alejandro Alonso
1515498a23 🐛 Fix storybook build 2024-08-06 10:46:37 +02:00
Andrey Antukh
d0059cbe29 Merge pull request #4952 from penpot/ladybenko-8439-storybook-build
Storybook build
2024-08-06 10:25:18 +02:00
sangpil hwang
34cf6e9e58 🌐 Add translations for: Korean.
Currently translated at 15.8% (223 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ko/
2024-08-05 21:09:25 +02:00
Nima K
05e283baec 🌐 Add translations for: Persian.
Currently translated at 50.0% (705 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fa/
2024-08-05 21:09:24 +02:00
Belén Albeza
457da6f23e Append timestamp to CSS import in storybook 2024-08-05 17:39:57 +02:00
Andrey Antukh
0f16f65d30 🔧 Update script names and conditionally build storybook 2024-08-05 17:39:37 +02:00
Eva Marco
1c2b6f5ab5 Merge pull request #4938 from penpot/ladybenko-7879-ds-input
🎉 Implement input* component
2024-08-05 08:58:53 +02:00
Eva Marco
f011d94339 🐛 Fix error on padding input props 2024-08-02 14:14:51 +02:00
Eva Marco
d527bbd8b5 🐛 Fix fill collapsed options 2024-08-02 11:12:28 +02:00
Belén Albeza
2015c484d0 📚 Add Input component documentation 2024-08-02 11:08:20 +02:00
Belén Albeza
480d5ba7c3 🎉 Implement input* component 2024-08-02 11:08:20 +02:00
Eva Marco
6b3bfc85b3 🐛 Fix scroll on color picker modal 2024-08-02 09:30:42 +02:00
Belén Albeza
2b2bc73564 🔧 Update build script to include storybook 2024-08-01 16:11:01 +02:00
Belén Albeza
7cdfd5a6d3 Watch css assets specifically for storybook 2024-08-01 15:31:23 +02:00
Belén Albeza
8bcc2a4932 Compile storybook target in release and a separate DS stylesheet 2024-08-01 15:29:02 +02:00
Belén Albeza
deef8abca5 🔧 Enable storybook to be served from a subdir 2024-08-01 15:29:02 +02:00
Belén Albeza
f683d65990 Merge pull request #4949 from penpot/niwinz-update-beicon
⬆️ Update dependencies
2024-07-31 16:54:04 +02:00
Andrey Antukh
93ec352f4a ⬆️ Update shadown-cljs and beicon dependency
Fixes compatibility issues between shadow-cljs :esm build and beicon
library.
2024-07-31 16:30:22 +02:00
Andrey Antukh
e0b009c538 ⬆️ Update yarn version to 4.3.1 2024-07-31 16:30:22 +02:00
Andrey Antukh
5c61d874be Merge remote-tracking branch 'origin/develop' into develop 2024-07-31 12:47:05 +02:00
Andrey Antukh
5cf64c1440 Merge remote-tracking branch 'origin/staging' into develop 2024-07-31 12:46:47 +02:00
Alejandro
ed91c7ca32 Merge pull request #4689 from penpot/niwinz-devenv-upgrade
⬆️ Upgrade devenv linux distribution version
2024-07-31 10:46:27 +02:00
Andrey Antukh
fdbec9917c Merge pull request #4946 from june128/fix-stuck-progress-bar
Revert "🐛 Set proper default tenant on exporter"
2024-07-31 10:15:28 +02:00
Julian Schacher
5ae28da709 Revert "🐛 Set proper default tenant on exporter"
This reverts commit 86b2ce4dab.
2024-07-31 00:32:48 +02:00
Belén Albeza
dba94237dc Merge pull request #4912 from penpot/eva-remove-old-tokens
♻️ Remove unused tokens
2024-07-30 12:03:07 +02:00
Alejandro
802846a838 Merge pull request #4929 from penpot/niwinz-snapshoting-improvements
 Improve file snapshoting mechanism
2024-07-30 08:15:09 +02:00
Andrey Antukh
c2aa4f4893 Merge pull request #4936 from n-stha/n-stha-fix-spelling
📎 Correct a spelling in onboarding.edn
2024-07-29 15:23:18 +02:00
n-stha
25c875dc55 📎 Correct a spelling in onboarding.edn 2024-07-29 18:52:40 +05:45
Eva Marco
2c5289d338 ♻️ Remove duplicated color tokens 2024-07-29 11:05:14 +02:00
Alejandro
00c5d58203 Merge pull request #4903 from penpot/palba-bugfixing-010
🐛 Fix Components are not dragged from the group to the assets tab
2024-07-29 10:34:28 +02:00
Andrey Antukh
5cf54c6384 Improve file snapshoting mechanism 2024-07-29 10:19:34 +02:00
Eva Marco
7c75af83b3 Merge pull request #4904 from penpot/eva-substitude-loader-component
♻️  Replacing the old Pencil loader with the new Loader component
2024-07-29 10:08:08 +02:00
Belén Albeza
39b2c1722a ♻️ Refactor loader* component props & usage 2024-07-29 09:20:06 +02:00
Andrey Antukh
40910703ee Merge pull request #4930 from penpot/ladybenko-8413-asset-ids
Assert icon and svg IDs in DS components
2024-07-29 08:45:53 +02:00
Belén Albeza
cfc01e03f6 Assert existing icon ID for button* and icon-button* 2024-07-26 14:33:11 +02:00
Belén Albeza
10ef9d696c Assert valid svg id in raw-svg* 2024-07-26 14:24:47 +02:00
Belén Albeza
138ece085e Assert existing icon ID for icon* 2024-07-26 14:24:47 +02:00
alonso.torres
19b2f330dd Merge remote-tracking branch 'origin/plugins-beta-test' into develop 2024-07-26 13:47:12 +02:00
Andrey Antukh
e48aa909da Merge pull request #4919 from penpot/ladybenko-7869-ds-buttons
Implement design system buttons
2024-07-26 13:18:21 +02:00
Andrey Antukh
b122db447a Merge pull request #4928 from penpot/alotor-plugins-10
Alotor plugins 10
2024-07-26 13:17:16 +02:00
alonso.torres
642c4fc9d1 ⬆️ Update plugins runtime 2024-07-26 12:42:31 +02:00
alonso.torres
4d57f33371 Change local storage access 2024-07-26 12:42:31 +02:00
alonso.torres
60c63e4558 Add undo block api to plugins 2024-07-26 12:42:31 +02:00
alonso.torres
aa90232bf9 Add export method into API 2024-07-26 12:42:31 +02:00
Belén Albeza
cf7439b1b4 📚 Add buttons documentation for the design system 2024-07-26 11:49:51 +02:00
Belén Albeza
60cba6c9f3 Implement button* and icon-button* for the design system 2024-07-26 11:49:51 +02:00
Andrey Antukh
3eaa997145 Merge remote-tracking branch 'origin/staging' into develop 2024-07-26 08:36:30 +02:00
AlexTECPlayz
28cca332e7 🌐 Add translations for: Romanian.
Currently translated at 90.4% (1274 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ro/
2024-07-25 19:09:17 +02:00
Andrey Antukh
025034cb71 Merge remote-tracking branch 'origin/staging' into develop 2024-07-25 11:23:42 +02:00
Andrey Antukh
7fd75336a5 Merge pull request #4918 from penpot/alotor-plugins-9
Alotor plugins 9
2024-07-25 11:04:22 +02:00
Eva Marco
af5a189d04 ♻️ Replacing the old Pencil loader with the new Loader component 2024-07-24 17:06:13 +02:00
AlexTECPlayz
7ec80a375a 🌐 Add translations for: Romanian.
Currently translated at 90.1% (1269 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ro/
2024-07-24 16:09:21 +02:00
alonso.torres
285119b2e5 ⬆️ Update plugins runtime 2024-07-24 13:43:50 +02:00
Pablo Alba
0539337121 🐛 Fix user cannot close comment creation tool 2024-07-24 09:22:53 +02:00
Pablo Alba
50fe715fba 🐛 Fix Components are not dragged from the group to the assets tab 2024-07-24 09:20:54 +02:00
Eva Marco
e5daa00d73 Add elevation tokens to ds 2024-07-24 09:00:03 +02:00
Belén Albeza
fd58813ec9 Merge pull request #4908 from penpot/eva-add-zindex-to-ds
 Add z-index tokens to the ds
2024-07-24 08:56:35 +02:00
Andrey Antukh
111add1ed6 🐛 Fix issue on merging stanging to develop 2024-07-24 08:40:31 +02:00
Eva Marco
12d65c7743 Add z-index tokens to the ds 2024-07-24 08:30:46 +02:00
Andrey Antukh
a100d1d11a Merge remote-tracking branch 'origin/staging' into develop 2024-07-24 08:20:36 +02:00
Andrey Antukh
28c4053ad3 Merge pull request #4914 from penpot/bameda-patch-1
📎 Add Contributing to the TOC
2024-07-23 21:16:59 +02:00
David Barragán Merino
e84d9358d1 📎 Add Contributing to the TOC 2024-07-23 21:15:39 +02:00
alonso.torres
2d25df33ce Add write methods to prototype API 2024-07-23 16:55:32 +02:00
Andrey Antukh
c51778f391 Merge pull request #4910 from penpot/ladybenko-8394-fix-sourcesans
🐛 Fix font declarations for Source Sans
2024-07-23 16:04:36 +02:00
Belén Albeza
20333d8179 🐛 Fix font declarations for Source Sans 2024-07-23 14:24:04 +02:00
alonso.torres
6454e878dd Page functions for plugins api 2024-07-22 13:10:10 +02:00
alonso.torres
d13b9ef3ea 🐛 Fix wrap not working in plugins 2024-07-22 11:27:29 +02:00
alonso.torres
26fa2a71ea 🐛 Fix problem with reset alignment on change text 2024-07-22 11:27:12 +02:00
Andrey Antukh
46ed61f070 Merge pull request #4878 from penpot/alotor-plugins-8
Alotor plugins 8
2024-07-22 11:17:03 +02:00
Eva Marco
09cd45fd8b Merge pull request #4876 from penpot/ladybenko-7914-spacing-tokens
 Add spacing tokens to the design system
2024-07-22 08:11:54 +02:00
Eva Marco
d162e3e11b Merge pull request #4879 from penpot/ladybenko-8349-storybook-theme
 Enable themes in Storybook
2024-07-22 07:47:46 +02:00
Belén Albeza
a5dd2683cd 💄 Remove deprecated StoryWrapper helper component 2024-07-12 14:05:44 +02:00
Belén Albeza
ebda46f748 Support theme switching within Storybook 2024-07-12 14:05:44 +02:00
Belén Albeza
0d8c98dcfe ⬆️ Upgrade storybook (patch version) 2024-07-12 14:05:44 +02:00
Belén Albeza
174ca6bed5 Merge pull request #4870 from penpot/eva-add-loader-component-to-ds
  Add loader component to ds
2024-07-12 14:04:10 +02:00
Eva Marco
271be57c99 Add loader component to the ds 2024-07-12 13:51:33 +02:00
alonso.torres
423d2fbb92 ⬆️ Update plugins runtime 2024-07-12 13:36:00 +02:00
alonso.torres
21b15167dd Add detach method to plugins 2024-07-12 13:36:00 +02:00
alonso.torres
59005e3bb8 Changes to plugin events 2024-07-12 13:36:00 +02:00
alonso.torres
60f637e947 Add parent property to shapes 2024-07-12 13:36:00 +02:00
alonso.torres
8ded4811bb Internal refactor of plugin installs 2024-07-12 13:36:00 +02:00
Eva Marco
3900b37f5c Merge pull request #4874 from penpot/ladybenko-8008-upgrade-storybook8
Upgrade to Storybook 8
2024-07-12 10:07:14 +02:00
TheScientistPT
cfb5a98cac 🌐 Add translations for: Portuguese (Portugal).
Currently translated at 99.5% (1402 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/pt_PT/
2024-07-11 22:09:23 +02:00
Nima K
03ddb32556 🌐 Add translations for: Persian.
Currently translated at 48.7% (686 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fa/
2024-07-11 22:09:22 +02:00
Belén Albeza
1398bcbc8c Add spacing tokens to the design system 2024-07-11 18:08:33 +02:00
Belén Albeza
93d9438f6c 📚 Adapts Heading docs/stories to be as the Text component 2024-07-11 17:06:15 +02:00
Belén Albeza
0fce6c5ebb 🐛 Fix broken typography docs after upgrading to v8 2024-07-11 17:01:04 +02:00
Belén Albeza
a03eeb63e7 ⬆️ Upgrade to storybook v8 2024-07-11 15:41:24 +02:00
Alejandro Alonso
4dd7880744 Add create-devenv command to manage.sh 2024-07-11 13:24:20 +02:00
Eva Marco
5ab7123566 Merge pull request #4865 from penpot/ladybenko-8347-storybook-controls
Use Storybook controls for stories
2024-07-11 13:06:56 +02:00
Belén Albeza
ba4732c526 🐛 Fix text component misbehaving when prop is empty string 2024-07-11 12:56:25 +02:00
Alejandro
73fb95976c Merge pull request #4863 from penpot/niwinz-refactor-backend-config
♻️ Refactor configuration validation
2024-07-11 12:27:59 +02:00
Belén Albeza
b473b7905d 🐛 Fix Text docs re: accessibility 2024-07-11 12:24:19 +02:00
Belén Albeza
ba36023ae6 Revamp RawSvg stories and update prop name 2024-07-11 10:06:46 +02:00
Alejandro Alonso
48e7cd28b3 Merge remote-tracking branch 'origin/staging' into develop 2024-07-11 09:24:17 +02:00
Alejandro
54711b0d25 Merge pull request #4864 from penpot/niwinz-kondo-fix
🐛 Fix exception on clj-kondo extension hook fn
2024-07-11 09:22:25 +02:00
Belén Albeza
7e61acc4da 💄 Update icon prop name 2024-07-10 16:15:07 +02:00
Belén Albeza
d7ca4d49dc Revamp icon stories 2024-07-10 15:53:27 +02:00
Belén Albeza
df858c2c7d 📎 Move icon and raw-svg components to a common subdir 2024-07-10 15:42:19 +02:00
Belén Albeza
9d3a282c0a 📎 Move typography-related components to their own folder 2024-07-10 15:33:38 +02:00
Andrey Antukh
9174bb140b ♻️ Refactor configuration validation
Replace spec with schema
2024-07-10 15:16:28 +02:00
Belén Albeza
54da6832f3 Revamp Text stories to display controls + rename tag prop to as 2024-07-10 13:34:09 +02:00
Belén Albeza
508f4fcd3c Revamp Heading stories to display controls 2024-07-10 13:31:56 +02:00
Andrey Antukh
eaaff76aad 🐛 Fix exception on clj-kondo extension hook fn
The exception is hidden on normal cli invocatin of clj-kondo
and hapens when component with empty params is defined.
2024-07-10 13:27:12 +02:00
Belén Albeza
0d0b5ead86 📎 Remove unused storybook addons + other libs 2024-07-10 12:44:15 +02:00
Belén Albeza
7f6bfacff1 Merge pull request #4857 from penpot/eva-add-text-component-to-storybook
 Add text component to storybook
2024-07-10 12:31:42 +02:00
Eva Marco
7bd5d31094 Add text component to storybook 2024-07-10 12:18:37 +02:00
Eva Marco
645bc32121 Add new heading component to the DS 2024-07-10 12:03:55 +02:00
Belén Albeza
6e55260160 Merge pull request #4851 from penpot/eva-add-heading-component-to-storybook
 Add heading component to storybook
2024-07-10 12:01:57 +02:00
Eva Marco
2abbb0d359 Add new heading component to the DS 2024-07-10 11:46:06 +02:00
Nima K
b13238eb30 🌐 Add translations for: Persian.
Currently translated at 47.9% (675 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fa/
2024-07-09 18:09:34 +02:00
Alejandro Alonso
f09cfedebc Merge remote-tracking branch 'origin/staging' into develop 2024-07-09 14:12:57 +02:00
Andrey Antukh
0a86d9d515 Merge remote-tracking branch 'origin/staging' into develop 2024-07-09 12:16:45 +02:00
Eva Marco
808ed6a98b Merge pull request #4853 from penpot/ladybenko-8291-update-assets
Update icons and svg assets (design system)
2024-07-09 08:12:36 +02:00
Eva Marco
2bb59671dd Merge pull request #4856 from penpot/ladybenko-8337-enable-ds-css-override
Enable design system CSS override + fix debug css compiling
2024-07-09 08:11:07 +02:00
Belén Albeza
fb6ebcd074 🐛 Fix debug css being included in prod builds 2024-07-08 15:57:35 +02:00
Belén Albeza
44a2a63fb8 Ensure DS scss modules are compiled before the app css modules 2024-07-08 15:57:35 +02:00
Belén Albeza
eae19e8252 📎 Remove leftover code 2024-07-08 15:57:35 +02:00
Andrey Antukh
1b05e7aa36 Merge pull request #4852 from penpot/alotor-plugins-7
 Small improvements over plugin manager
2024-07-08 09:04:44 +02:00
Belén Albeza
be9a2767ea 📎 Remove unused rocket icon 2024-07-05 15:28:25 +02:00
Belén Albeza
6a18791c30 Add character icons 2024-07-05 15:26:45 +02:00
alonso.torres
2cc3f65323 Small improvements over plugin manager 2024-07-05 15:16:09 +02:00
Belén Albeza
63d1b558d1 Add percentage icon and update puzzle icon 2024-07-05 15:09:01 +02:00
Belén Albeza
cfbfda925b 📚 Fix typo in RawSvg storybook docs 2024-07-05 14:57:22 +02:00
Belén Albeza
fd1ab29920 Update v2-related svg assets 2024-07-05 14:34:59 +02:00
alonso.torres
35f4a07d27 Merge remote-tracking branch 'origin/plugins-beta-test' into develop 2024-07-05 11:12:58 +02:00
Eva Marco
9ce3f6da45 Merge pull request #4845 from penpot/ladybenko-8265-raw-svg-component
RawSVG component (design system) + generate SVG sprite for assets
2024-07-05 09:44:35 +02:00
Belén Albeza
b8b199c5ec Merge pull request #4844 from penpot/eva-fix-visual-test
🐛  Fix workspace visual test for assets modal
2024-07-05 09:23:22 +02:00
Belén Albeza
e492284abe Merge pull request #4843 from penpot/eva-remove-unused-locale-fn
♻️  Remove unused locale fn
2024-07-05 09:22:24 +02:00
Eva Marco
3d5e064358 ♻️ Remove unused locale function 2024-07-05 09:04:34 +02:00
Andrey Antukh
6f8ce1fc5a Merge pull request #4849 from penpot/alotor-plugins-6
 Add events for plugins
2024-07-04 17:17:38 +02:00
Andrey Antukh
5ae30ea9bc Merge pull request #4850 from penpot/alotor-bug-api-svg
🐛 Fix problem when creating SVG images
2024-07-04 17:15:35 +02:00
Belén Albeza
8959d39356 Merge pull request #4837 from penpot/eva-ds-foundations-typography
 Add typography ds tokens
2024-07-04 16:11:25 +02:00
alonso.torres
aded9f1a36 🐛 Fix problem when creating SVG images 2024-07-04 16:01:02 +02:00
Belén Albeza
3a34eb1357 🐛 Fix flakiness of visual workspace test (assets tab) 2024-07-04 15:45:50 +02:00
alonso.torres
c2564eaf65 Change spec location 2024-07-04 15:16:58 +02:00
alonso.torres
53d3b2abbc Add events for plugins 2024-07-04 15:16:34 +02:00
Belén Albeza
5d90c463a3 📚 Add docs for RawSvg component 2024-07-04 14:48:57 +02:00
Belén Albeza
5309da2eee 📎 Add storybook helper components and improve current stories 2024-07-04 14:11:03 +02:00
Andrey Antukh
d1dd13fde9 Merge pull request #4842 from penpot/alotor-plugins-5
Alotor plugins 5
2024-07-04 13:59:48 +02:00
alonso.torres
0a83306015 ⬆️ Update plugins runtime 2024-07-04 13:57:04 +02:00
Belén Albeza
203a39f07c ♻️ Rename IconGrid to StoryGrid (storybook helper component) 2024-07-04 13:05:23 +02:00
Alejandro
85579b253f Merge pull request #4681 from penpot/niwinz-enhancements-2
🔥 Replace spec usage on RPC methods with schema
2024-07-04 12:56:41 +02:00
Eva Marco
1ca751bc42 🐛 Fix workspace visual test for assets modal 2024-07-04 12:41:48 +02:00
Andrey Antukh
f344eee778 🐛 Fix backend test initialization code 2024-07-04 12:30:28 +02:00
Andrey Antukh
28c2197ba7 ♻️ Add string length validation to backend RPC methods fields 2024-07-04 12:30:28 +02:00
Andrey Antukh
0721760900 Add better schema for shape export property 2024-07-04 12:30:28 +02:00
Andrey Antukh
45c77f97ce 📎 Fix code style issue not catched by the linter
Comment indentantion
2024-07-04 12:30:28 +02:00
Andrey Antukh
05fb46a573 Accept uri instances on http client 2024-07-04 12:30:28 +02:00
Andrey Antukh
ad6a864478 🔥 Replace spec with schema on search RPC methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
37fcc74ef8 🔥 Replace spec with schema on media RPC methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
c4cf745d77 🔥 Replace spec with schema on ldap RPC methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
85108672bf 🔥 Replace spec with schema on file-thumbnails RPC methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
969c9105fd 🔥 Replace spec with schema on feedback RPC methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
073621f29a 🔥 Replace spec with schema on demo RPC methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
bbc0089166 🔥 Replace spec with schema on verify-token RPC methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
268f1d40aa 🔥 Replace spec with schema on file-share RPC methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
e9a28b034f 🔥 Replace spec with schema on file RPC methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
bfca324623 🔥 Replace spec with schema on project rpc methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
279c6337e4 🔥 Replace spec with schema on access-token rpc methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
368917f7f5 🔥 Replace spec with schema on webhooks rpc methods 2024-07-04 12:30:28 +02:00
Andrey Antukh
f973faa409 📎 Add missing SPEC tag on doc entry template 2024-07-04 12:30:28 +02:00
Andrey Antukh
a0339132dd 📎 Update cljfmt config 2024-07-04 12:30:28 +02:00
Andrey Antukh
40f947fc9f 🐛 Fix issue with schema uri decoder 2024-07-04 12:30:28 +02:00
Andrey Antukh
d2bedec59c Unify naming of schema registering functions 2024-07-04 12:30:28 +02:00
alonso.torres
1b93ccdec9 Remove duplicate permissions in confirm dialog 2024-07-04 12:07:54 +02:00
Alejandro Alonso
2921b62b37 Merge remote-tracking branch 'origin/staging' into develop 2024-07-04 11:56:21 +02:00
alonso.torres
83f3ae1fbd Change plugins url 2024-07-04 11:52:31 +02:00
Eva Marco
66d97cb2e0 Add typography ds tokens 2024-07-04 11:18:05 +02:00
Belén Albeza
4ecaaba1e5 Add RawSvg component to the design system 2024-07-04 10:11:12 +02:00
Belén Albeza
c52da573c5 📎 Fix react warning on icon* component 2024-07-04 09:47:37 +02:00
Belén Albeza
4ac18e2ef0 🐛 Fix cursors svg duplicating icons sprites 2024-07-04 09:20:18 +02:00
Belén Albeza
f05e1354ff 🔧 Add assets svg sprite generation 2024-07-04 09:20:18 +02:00
Andrey Antukh
bafe2ab985 Merge pull request #4832 from penpot/ladybenko-7866-icon-component
Implement icon component (design system)
2024-07-03 19:33:16 +02:00
Andrey Antukh
0d13a12d64 Merge pull request #4840 from penpot/alotor-plugins-4
Alotor plugins 4
2024-07-03 16:49:47 +02:00
alonso.torres
deb0fab156 🐛 Fix small visual problems 2024-07-03 15:35:43 +02:00
Belén Albeza
c181887266 📎 Remove unused example simple_button component 2024-07-03 15:26:11 +02:00
Belén Albeza
a624a10c85 🐛 Fix scrolling not working on storybook mdx files 2024-07-03 15:26:11 +02:00
Belén Albeza
6295fbf7e2 Implement icon* component 2024-07-03 15:26:11 +02:00
Belén Albeza
c6a7ad0520 🐛 Fix template generation for storybook 2024-07-03 15:25:30 +02:00
Belén Albeza
de89dfe27f 📎 Remove unused legacy icons preview 2024-07-03 15:25:30 +02:00
alonso.torres
a8463f349a New plugin attributes 2024-07-03 15:23:05 +02:00
Belén Albeza
3b6ed823b9 Merge pull request #4839 from penpot/niwinz-rumext-linter
 Add better linter for rumext defc macro
2024-07-03 15:22:55 +02:00
alonso.torres
80e17f8cfc Add new signature for the run-store test helper 2024-07-03 15:22:42 +02:00
Andrey Antukh
8fae4550c3 Add better linter for rumext defc macro 2024-07-03 14:36:29 +02:00
Alejandro Alonso
9125b46ca5 Merge remote-tracking branch 'origin/staging' into develop 2024-07-03 08:46:26 +02:00
Alejandro
7ed25d2dba Merge pull request #4765 from penpot/niwinz-refactor-forms
♻️ Refactor forms (spec -> schema)
2024-07-03 08:45:42 +02:00
Andrey Antukh
0fa8aca6e2 Add minor improvements to common.schema ns 2024-07-03 08:25:51 +02:00
Andrey Antukh
7be79c10fd ♻️ Refactor forms
Mainly replace spec with schema with better
and more reusable validations
2024-07-03 08:25:51 +02:00
Andrey Antukh
f095e1b29f Replace custom all-spaces? fn with generic str/blank? 2024-07-02 17:47:58 +02:00
Andrey Antukh
96822082bd Revert " Rehash and sync translations"
This reverts commit 5b6fc19e00.
2024-07-02 17:47:29 +02:00
Aitor Moreno
c637912337 Merge pull request #4822 from penpot/niwinz-translation-management-script
🎉 Add new translations management script
2024-07-02 16:20:25 +02:00
AzazelN28
5b6fc19e00 Rehash and sync translations 2024-07-02 16:04:57 +02:00
Andrey Antukh
f6435461a1 Merge pull request #4835 from penpot/alotor-plugins-3
🐛 Fix some problems in plugins
2024-07-02 15:44:50 +02:00
AzazelN28
83e51abd35 🐛 Fix package.json translation scripts 2024-07-02 15:41:00 +02:00
Andrey Antukh
dab88404c0 Merge pull request #4834 from penpot/ladybenko-fix-layer-width
🐛 Fix layer width on the left sidebar
2024-07-02 15:37:22 +02:00
alonso.torres
c66ff74f21 🐛 Fix some problems in plugins 2024-07-02 15:30:35 +02:00
Belén Albeza
769655f565 🐛 Fix layer width on the left sidebar 2024-07-02 15:18:27 +02:00
Andrey Antukh
139dd7d80f 🎉 Add new translations management script 2024-07-02 15:11:56 +02:00
Andrey Antukh
62cea62356 Merge pull request #4816 from penpot/alotor-plugins-2
Improvements over plugins subsystem
2024-07-02 13:43:15 +02:00
alonso.torres
58fa10a0d5 ⬆️ Update plugins runtime 2024-07-02 11:08:56 +02:00
alonso.torres
395a91c00c Plugins permissions review 2024-07-02 11:01:43 +02:00
alonso.torres
741bf3b666 New plugins permissions dialog 2024-07-02 11:01:43 +02:00
alonso.torres
fbce59e81f Improved text handling in plugins 2024-07-02 10:41:06 +02:00
alonso.torres
ac58a5b8fa Improved transformation from and to JS for plugins 2024-07-02 10:41:06 +02:00
alonso.torres
42230f2630 Change shapes color 2024-07-02 10:41:06 +02:00
Belén Albeza
9a188fd792 Merge pull request #4830 from penpot/eva-ds-color-foundations
 Add DS foundation colors
2024-07-01 16:04:24 +02:00
Eva Marco
6c68a34d63 Add DS foundation colors 2024-07-01 15:10:46 +02:00
Eva Marco
746b448f30 Merge pull request #4825 from penpot/ladybenko-8224-setup-ds
Setup design system
2024-07-01 12:49:22 +02:00
Belén Albeza
b5aba58aac Make storybook wrapper to render both dark and light themes 2024-07-01 11:14:42 +02:00
Belén Albeza
2bb7726180 📎 Remove unneeded icons export in the storybook target 2024-07-01 11:14:42 +02:00
Belén Albeza
24b607cad3 💄 Move the stub design system component to its own ds folder 2024-07-01 11:14:42 +02:00
Eva Marco
087d0e90e6 Merge pull request #4821 from penpot/ladybenko-8182-prettier
Add prettier for JS files
2024-07-01 10:48:01 +02:00
Belén Albeza
e448951d6f Add CI rule for checking JS format 2024-07-01 10:29:57 +02:00
Belén Albeza
ecbedf847f 💄 Reformat affected JS files 2024-07-01 10:29:57 +02:00
Belén Albeza
3efd5cb9e8 Add prettier JS commands to package.json 2024-07-01 10:29:57 +02:00
Belén Albeza
e1dc964c4c Upgrade prettier and use specific settings for scss files only 2024-07-01 10:23:19 +02:00
The_BadUser
295c932646 🌐 Add translations for: Russian.
Currently translated at 99.6% (1403 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ru/
2024-06-30 21:10:08 +02:00
The_BadUser
5b9f4128f3 🌐 Add translations for: Russian.
Currently translated at 89.3% (1258 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ru/
2024-06-29 01:26:20 +02:00
The_BadUser
100f1229ce 🌐 Add translations for: Russian.
Currently translated at 75.9% (1070 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ru/
2024-06-29 00:09:23 +02:00
Aryiu
adf24cd274 🌐 Add translations for: Catalan.
Currently translated at 77.1% (1086 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ca/
2024-06-29 00:09:22 +02:00
Andrey Antukh
de1d154e9c Merge pull request #4824 from penpot/alotor-fix-plugins
🐛 Fix problem with recursive properties
2024-06-28 16:21:58 +02:00
alonso.torres
4345584384 🐛 Fix problem with recursive properties 2024-06-28 14:57:14 +02:00
Alejandro Alonso
ba1adf91ca Merge remote-tracking branch 'origin/staging' into develop 2024-06-28 11:09:37 +02:00
Andrey Antukh
024b08de06 Merge remote-tracking branch 'origin/staging' into develop 2024-06-28 10:37:22 +02:00
Alejandro
4e5eabbf05 Merge pull request #4781 from penpot/ladybenko-8110-clean-global-css
 Clean global css styles
2024-06-28 08:48:21 +02:00
Belén Albeza
c9258b5526 Remove workspace partial scss stylesheet 2024-06-27 15:35:57 +02:00
Belén Albeza
ce9fb80558 📎 Remove unused css for loader 2024-06-27 15:35:57 +02:00
Belén Albeza
cd8e2540de Use CSS modules for styling the debug icons preview page 2024-06-27 15:35:57 +02:00
Belén Albeza
9a2ee806e4 Clean up base scss 2024-06-27 15:35:57 +02:00
Belén Albeza
b192887d19 Remove framework scss stylesheet 2024-06-27 15:35:57 +02:00
Belén Albeza
b6e918b024 Remove unused legacy sass files 2024-06-27 15:35:57 +02:00
Belén Albeza
ed174d16d1 Remove unused animation mixin 2024-06-27 15:35:57 +02:00
Belén Albeza
6b8108afda Make reset css to be included first thing in our styles 2024-06-27 15:35:57 +02:00
Belén Albeza
49fd000217 Clean up fonts scss files 2024-06-27 15:35:57 +02:00
Belén Albeza
0c3f47b0c3 Clean up unused selectors / mixins / sass vars 2024-06-27 15:35:57 +02:00
Belén Albeza
2d53b96a15 Initial clean up of framework scss 2024-06-27 15:35:57 +02:00
Belén Albeza
540875c41e Remove unused css var colors 2024-06-27 15:35:57 +02:00
Belén Albeza
595f153d85 Remove importing animate.css 2024-06-27 15:35:57 +02:00
Belén Albeza
0cbc3487b0 🔧 Tweak the pixel diff ratio of playwright 2024-06-27 15:35:57 +02:00
Alejandro Alonso
978ac68474 Merge remote-tracking branch 'origin/staging' into develop 2024-06-27 09:54:48 +02:00
Alejandro Alonso
045e83e871 Merge remote-tracking branch 'origin/staging' into develop 2024-06-27 08:44:23 +02:00
Andrey Antukh
0239139b4b Merge pull request #4802 from penpot/jordisala1991-feature/no-direct-download
 Return blob when exporting using the lib-penpot
2024-06-27 07:59:38 +02:00
Alejandro
8c411e7727 Merge pull request #4808 from penpot/ladybenko-fix-playwright-test-mac-shortcut
🐛 Fix playwright test mac shortcut
2024-06-27 07:48:36 +02:00
Belén Albeza
16d0b925fa 🐛 Fix workspace 'make group' test on Mac 2024-06-26 17:02:24 +02:00
Belén Albeza
f306ddb51f 🐛 Fix onboarding playwright test on CI mode 2024-06-26 17:01:58 +02:00
Andrey Antukh
4faf9bbff1 📎 Add minor change on how promise is created from observable 2024-06-26 11:27:30 +02:00
Jordi Sala Morales
44b6d1a516 Return blob when exporting using the lib-penpot 2024-06-26 11:19:09 +02:00
Alejandro Alonso
4ed6e1e8ec Merge remote-tracking branch 'origin/staging' into develop 2024-06-26 07:42:50 +02:00
Alejandro
4437fc43e4 Merge pull request #4799 from penpot/ladybenko-fix-visual-regression-tests
Fix broken visual regression test + refactor Dashboard POM
2024-06-26 07:01:49 +02:00
Andrey Antukh
253e5a11fc Merge remote-tracking branch 'origin/staging' into develop 2024-06-25 16:33:52 +02:00
Alejandro Alonso
6e734f2eac Merge remote-tracking branch 'origin/staging' into develop 2024-06-25 15:54:32 +02:00
Belén Albeza
30edca024a Remove unneeded draftsFile and newFile locators in dashboard POM 2024-06-25 15:26:49 +02:00
Belén Albeza
c14f783d94 Remove redundant locators for Dashboard POM 2024-06-25 15:16:13 +02:00
Belén Albeza
8f3452c0af Avoid using unneeded test ids in dashboard POM 2024-06-25 14:57:37 +02:00
Belén Albeza
97a1b59861 💄 Reformat DashboardPage.js according to prettier rules 2024-06-25 11:56:31 +02:00
Alejandro Alonso
41aad7558b Merge remote-tracking branch 'origin/staging' into develop 2024-06-25 10:49:32 +02:00
Alejandro Alonso
d48616d510 Merge remote-tracking branch 'origin/staging' into develop 2024-06-25 10:18:42 +02:00
Andrey Antukh
8296e72887 Merge pull request #4793 from penpot/alotor-plugins-2
 Add some missing text properties in plugins
2024-06-25 07:47:34 +02:00
Oğuz Ersen
2648e71f5b 🌐 Add translations for: Turkish.
Currently translated at 100.0% (1408 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/tr/
2024-06-24 21:09:19 +02:00
alonso.torres
5771f2f8aa Plugins retrieve selection colors 2024-06-24 15:26:47 +02:00
alonso.torres
f86156b619 Plugins support for code generation 2024-06-24 15:26:21 +02:00
alonso.torres
8ff0015458 Add to plugins connect and fetch libraries 2024-06-24 12:34:35 +02:00
alonso.torres
84ecb99400 Add some missing text properties in plugins 2024-06-24 09:57:57 +02:00
Stas Haas
5160ae364d 🌐 Add translations for: German.
Currently translated at 100.0% (1408 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-06-22 10:09:13 +02:00
Andrey Antukh
b9e40b4d82 Merge pull request #4788 from penpot/alotor-plugins-2
Fix problem with plugins initialization
2024-06-21 14:58:42 +02:00
alonso.torres
4b67c0593d Upload media with data in plugins 2024-06-21 12:46:31 +02:00
alonso.torres
fb1429956a Changed order of plugins initialization 2024-06-21 12:44:35 +02:00
Andrey Antukh
c70d20f95d Merge pull request #4783 from penpot/alotor-plugins-texts
Update plugins
2024-06-21 10:03:52 +02:00
alonso.torres
47d211cd87 ⬆️ Update plugin runtime 2024-06-21 09:29:09 +02:00
alonso.torres
7fd223893b Expose component properties in components 2024-06-21 09:29:09 +02:00
alonso.torres
1794859468 Review input validation for plugins 2024-06-21 09:29:09 +02:00
alonso.torres
c5c8be4b4a Improve input validation in plugins 2024-06-21 09:29:09 +02:00
alonso.torres
e13d543dcd Add geometry utils 2024-06-21 09:29:09 +02:00
alonso.torres
69fad7a920 Add some utilities for fonts in plugins 2024-06-21 09:29:09 +02:00
alonso.torres
2da5dcb619 Add text ranges support in plugins 2024-06-21 09:29:09 +02:00
Stas Haas
3260130042 🌐 Add translations for: German.
Currently translated at 99.8% (1406 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-06-21 07:09:15 +00:00
Unreal Vision
c77316f91e 🌐 Add translations for: French.
Currently translated at 100.0% (1408 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fr/
2024-06-21 07:09:14 +00:00
Pablo Alba
018464aedf ♻️ Unify move shape on workspace and relocate on layers panel 2024-06-20 16:00:39 +02:00
Andrey Antukh
2982dde7df Merge pull request #4776 from penpot/SudoVanilla-patch-1
🔥 Remove version specification from docker-compose.yaml file
2024-06-20 08:28:04 +02:00
SudoVanilla
acb7ca5440 🔥 Remove version specification from docker-compose.yaml file
It is deprecated
2024-06-20 08:16:02 +02:00
Yaron Shahrabani
8a7fdaa6ca 🌐 Add translations for: Hebrew.
Currently translated at 100.0% (1408 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
2024-06-19 22:09:19 +02:00
Stas Haas
27c574f0a7 🌐 Add translations for: German.
Currently translated at 99.5% (1401 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-06-19 22:09:18 +02:00
Unreal Vision
6d82d54560 🌐 Add translations for: French.
Currently translated at 96.6% (1361 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fr/
2024-06-19 22:09:17 +02:00
Alejandro Alonso
cba62c0172 Merge remote-tracking branch 'origin/staging' into develop 2024-06-19 08:12:19 +02:00
Alejandro Alonso
47b455ba87 Merge remote-tracking branch 'origin/staging' into develop 2024-06-18 16:57:51 +02:00
Stephan Paternotte
3f29071139 🌐 Add translations for: Dutch.
Currently translated at 100.0% (1408 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/nl/
2024-06-18 15:09:24 +02:00
Yaron Shahrabani
ccdfac7b8e 🌐 Add translations for: Hebrew.
Currently translated at 96.2% (1355 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
2024-06-18 15:09:23 +02:00
Stas Haas
be959ca90c 🌐 Add translations for: German.
Currently translated at 98.7% (1391 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-06-18 15:09:22 +02:00
Brendan Bell
2929783d35 📎 Update docker-compose.yaml 2024-06-17 13:30:51 +02:00
Andrey Antukh
838843be45 Merge branch 'translations' into develop 2024-06-17 10:09:05 +02:00
Anonymous
1225d72917 🌐 Add translations for: Yoruba.
Currently translated at 85.2% (1200 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/yo/
2024-06-17 10:07:39 +02:00
Anonymous
9c4a310d84 🌐 Add translations for: Igbo.
Currently translated at 37.1% (523 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ig/
2024-06-17 10:07:39 +02:00
Anonymous
d3e9fd9a36 🌐 Add translations for: Malay.
Currently translated at 48.1% (678 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ms/
2024-06-17 10:07:39 +02:00
Anonymous
d2c63e0857 🌐 Add translations for: Spanish (Latin America).
Currently translated at 9.5% (134 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/es_419/
2024-06-17 10:07:39 +02:00
Anonymous
52c00367d7 🌐 Add translations for: Hausa.
Currently translated at 89.9% (1267 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ha/
2024-06-17 10:07:39 +02:00
Anonymous
6ee844b48f 🌐 Add translations for: Afrikaans.
Currently translated at 6.8% (97 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/af/
2024-06-17 10:07:39 +02:00
Anonymous
542ad58c32 🌐 Add translations for: Dutch.
Currently translated at 96.7% (1362 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/nl/
2024-06-17 10:07:38 +02:00
Anonymous
4781cf1037 🌐 Add translations for: Latvian.
Currently translated at 96.3% (1357 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/lv/
2024-06-17 10:07:38 +02:00
Anonymous
5aa3b432bf 🌐 Add translations for: Korean.
Currently translated at 15.5% (219 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ko/
2024-06-17 10:07:38 +02:00
Anonymous
47401aae99 🌐 Add translations for: Bengali.
Currently translated at 1.0% (15 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/bn/
2024-06-17 10:07:37 +02:00
Anonymous
27473003b7 🌐 Add translations for: Faroese.
Currently translated at 11.2% (159 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fo/
2024-06-17 10:07:37 +02:00
Anonymous
fa8bc7d40d 🌐 Add translations for: Ukrainian (ukr_UA).
Currently translated at 14.9% (210 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
2024-06-17 10:07:37 +02:00
Anonymous
f352cdf9a3 🌐 Add translations for: Croatian.
Currently translated at 72.2% (1017 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/hr/
2024-06-17 10:07:37 +02:00
Anonymous
3d68d454fe 🌐 Add translations for: Tamil.
Currently translated at 3.2% (46 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ta/
2024-06-17 10:07:37 +02:00
Anonymous
9a9eca7813 🌐 Add translations for: Portuguese (Portugal).
Currently translated at 94.6% (1332 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/pt_PT/
2024-06-17 10:07:36 +02:00
Anonymous
f3d82c915b 🌐 Add translations for: Finnish.
Currently translated at 3.9% (55 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fi/
2024-06-17 10:07:36 +02:00
Anonymous
5185d1eaa5 🌐 Add translations for: Czech.
Currently translated at 92.8% (1307 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/cs/
2024-06-17 10:07:36 +02:00
Anonymous
6abf792e0f 🌐 Add translations for: Basque.
Currently translated at 83.4% (1175 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/eu/
2024-06-17 10:07:36 +02:00
Anonymous
4d56f86719 🌐 Add translations for: Japanese.
Currently translated at 16.6% (235 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ja/
2024-06-17 10:07:35 +02:00
Anonymous
f033814f96 🌐 Add translations for: Galician.
Currently translated at 26.7% (376 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/gl/
2024-06-17 10:07:35 +02:00
Anonymous
2e3dbfeb27 🌐 Add translations for: Lithuanian.
Currently translated at 8.4% (119 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/lt/
2024-06-17 10:07:35 +02:00
Anonymous
a50e431c7a 🌐 Add translations for: Polish.
Currently translated at 81.3% (1146 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/pl/
2024-06-17 10:07:35 +02:00
Anonymous
59e18e8d4c 🌐 Add translations for: Italian.
Currently translated at 32.2% (454 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/it/
2024-06-17 10:07:34 +02:00
Anonymous
731299fe60 🌐 Add translations for: Persian.
Currently translated at 47.8% (674 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fa/
2024-06-17 10:07:34 +02:00
Anonymous
5cb2c1bbe4 🌐 Add translations for: Malayalam.
Currently translated at 3.7% (53 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ml/
2024-06-17 10:07:34 +02:00
Anonymous
5362d9f5e9 🌐 Add translations for: Chinese (Traditional).
Currently translated at 45.8% (646 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/zh_Hant/
2024-06-17 10:07:34 +02:00
Anonymous
981cd92b26 🌐 Add translations for: Hebrew.
Currently translated at 96.0% (1353 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
2024-06-17 10:07:34 +02:00
Anonymous
77b70cac60 🌐 Add translations for: Indonesian.
Currently translated at 96.0% (1352 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/id/
2024-06-17 10:07:33 +02:00
Anonymous
ac8775565b 🌐 Add translations for: Arabic.
Currently translated at 80.0% (1127 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ar/
2024-06-17 10:07:33 +02:00
Anonymous
5651b72c0f 🌐 Add translations for: Romanian.
Currently translated at 90.0% (1268 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ro/
2024-06-17 10:07:33 +02:00
Anonymous
3e54ab1c3c 🌐 Add translations for: Danish.
Currently translated at 7.4% (105 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/da/
2024-06-17 10:07:33 +02:00
Anonymous
81482c8350 🌐 Add translations for: German.
Currently translated at 97.0% (1367 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-06-17 10:07:32 +02:00
Anonymous
9f25c6eb09 🌐 Add translations for: Portuguese (Brazil).
Currently translated at 81.3% (1145 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/pt_BR/
2024-06-17 10:07:32 +02:00
Anonymous
4d778e71fe 🌐 Add translations for: Chinese (Simplified).
Currently translated at 95.8% (1349 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/zh_Hans/
2024-06-17 10:07:32 +02:00
Anonymous
36d0e6eb36 🌐 Add translations for: Turkish.
Currently translated at 97.1% (1368 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/tr/
2024-06-17 10:07:32 +02:00
Anonymous
492a975a3a 🌐 Add translations for: Russian.
Currently translated at 56.1% (790 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ru/
2024-06-17 10:07:31 +02:00
Anonymous
ac14a6315b 🌐 Add translations for: Greek.
Currently translated at 36.9% (520 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/el/
2024-06-17 10:07:31 +02:00
Anonymous
37abe7d7f1 🌐 Add translations for: French.
Currently translated at 96.3% (1356 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fr/
2024-06-17 10:07:31 +02:00
Anonymous
0cebd89c01 🌐 Add translations for: Catalan.
Currently translated at 75.0% (1057 of 1408 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ca/
2024-06-17 10:07:30 +02:00
Hosted Weblate
2f49b419bd Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/
2024-06-17 10:02:54 +02:00
Stephan Paternotte
c144a20012 🌐 Add translations for: Dutch.
Currently translated at 100.0% (1390 of 1390 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/nl/
2024-06-17 10:02:52 +02:00
Stas Haas
1cf79fb56e 🌐 Add translations for: German.
Currently translated at 99.9% (1389 of 1390 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2024-06-17 10:02:52 +02:00
Oğuz Ersen
68724e6236 🌐 Add translations for: Turkish.
Currently translated at 100.0% (1390 of 1390 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/tr/
2024-06-17 10:02:52 +02:00
Andrey Antukh
f529b339c6 Merge remote-tracking branch 'origin/staging' into develop 2024-06-17 10:02:34 +02:00
Alejandro Alonso
b991391667 Merge remote-tracking branch 'origin/staging' into develop 2024-06-14 08:10:51 +02:00
Andrey Antukh
88540eeedd Merge remote-tracking branch 'origin/staging' into develop 2024-06-14 07:45:53 +02:00
Alejandro Alonso
7e87362a39 Merge remote-tracking branch 'origin/staging' into develop 2024-06-13 11:04:58 +02:00
Belén Albeza
c6da42ee35 Merge pull request #4721 from penpot/alotor-bugfix
🐛 Fix problem moving layout to frame
2024-06-11 15:06:08 +02:00
alonso.torres
f88bb4e204 🐛 Fix problem moving layout to frame 2024-06-11 14:55:00 +02:00
Andrey Antukh
c0919aff51 Merge remote-tracking branch 'origin/staging' into develop 2024-06-11 11:27:16 +02:00
Alejandro Alonso
3bb5db6490 Merge remote-tracking branch 'origin/staging' into develop 2024-06-11 07:34:48 +02:00
alonso.torres
33166032f1 ⬆️ Update plugins runtime 2024-06-10 15:12:51 +02:00
alonso.torres
5233654da2 Add support for plugin data into penpot objects 2024-06-10 15:12:51 +02:00
alonso.torres
4d4a3a512d 💄 Style changes to the plugins modal 2024-06-10 15:12:51 +02:00
alonso.torres
411fe5448b 🐛 Fix rename layers for plugins 2024-06-10 15:12:51 +02:00
Pablo Alba
f052c81ee1 🐛 Fix issue with annotation menu rerendering (2) 2024-06-07 13:08:43 +02:00
Pablo Alba
b170a619cd Merge pull request #4695 from penpot/niwinz-bugfix-annotations
🐛 Fix issue with annotation menu rerendering
2024-06-07 13:06:40 +02:00
Andrey Antukh
4d2f82e03a 🐛 Fix issue with annotation menu rerendering 2024-06-07 12:55:33 +02:00
alonso.torres
da738ba1e9 Merge remote-tracking branch 'origin/staging' into develop 2024-06-07 12:21:57 +02:00
Belén Albeza
2f84978274 Merge pull request #4687 from penpot/superalex-e2e-tests-color-palette
 Add e2e tests for fix color palette default library
2024-06-06 15:27:48 +02:00
Andrey Antukh
1d88c7e92d ⬆️ Upgrade devenv linux distribution version
We pass from ubuntu 22.04 LTS to Debian 12 (bookworm)
Update postgresql from 15 to 16
Update JVM21 to the latest minor version
2024-06-06 15:06:16 +02:00
Alejandro Alonso
5af9bb1cdb Add e2e tests for fix color palette default library 2024-06-06 12:54:31 +02:00
Andrey Antukh
c8130e9453 Send profile zoom and vport/vbox on presence notifications 2024-06-06 12:02:43 +02:00
Andrés Moya
ccd687cbf3 Merge branch 'staging' into develop 2024-06-06 11:21:42 +02:00
Alejandro Alonso
ca73a79cfe 📎 Prepare new development cycle 2024-06-05 12:46:11 +02:00
1649 changed files with 148990 additions and 110951 deletions

View File

@@ -1,6 +1,124 @@
version: 2
version: 2.1
jobs:
build:
test-common:
docker:
- image: penpotapp/devenv:latest
working_directory: ~/repo
resource_class: medium+
environment:
JAVA_OPTS: -Xmx4g -Xms100m -XX:+UseSerialGC
NODE_OPTIONS: --max-old-space-size=4096
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "common/deps.edn"}}
- run:
name: "fmt check & linter"
working_directory: "./common"
command: |
yarn install
yarn run fmt:clj:check
yarn run lint:clj
- run:
name: "JVM tests"
working_directory: "./common"
command: |
clojure -M:dev:test
- save_cache:
paths:
- ~/.m2
key: v1-dependencies-{{ checksum "common/deps.edn"}}
test-frontend:
docker:
- image: penpotapp/devenv:latest
working_directory: ~/repo
resource_class: medium+
environment:
JAVA_OPTS: -Xmx4g -Xms100m -XX:+UseSerialGC
NODE_OPTIONS: --max-old-space-size=4096
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "frontend/deps.edn"}}
- run:
name: "prepopulate linter cache"
working_directory: "./common"
command: |
yarn install
yarn run lint:clj
- run:
name: "fmt check & linter"
working_directory: "./frontend"
command: |
yarn install
yarn run fmt:clj:check
yarn run fmt:js:check
yarn run lint:scss
yarn run lint:clj
- run:
name: "unit tests"
working_directory: "./frontend"
command: |
yarn install
yarn run test
- save_cache:
paths:
- ~/.m2
key: v1-dependencies-{{ checksum "frontend/deps.edn"}}
test-integration:
docker:
- image: penpotapp/devenv:latest
working_directory: ~/repo
resource_class: large
environment:
JAVA_OPTS: -Xmx6g -Xms2g
NODE_OPTIONS: --max-old-space-size=4096
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "frontend/deps.edn"}}
- run:
name: "integration tests"
working_directory: "./frontend"
command: |
yarn install
yarn run build:app:assets
yarn run build:app
yarn run build:app:libs
yarn run playwright install --with-deps chromium
yarn run test:e2e -x --workers=4
test-backend:
docker:
- image: penpotapp/devenv:latest
- image: cimg/postgres:14.5
@@ -20,103 +138,30 @@ jobs:
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "backend/deps.edn" }}-{{ checksum "frontend/deps.edn"}}-{{ checksum "common/deps.edn"}}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run: cd .clj-kondo && cat config.edn
- run: cat .cljfmt.edn
- run: clj-kondo --version
keys:
- v1-dependencies-{{ checksum "backend/deps.edn" }}
- run:
name: "backend fmt check"
working_directory: "./backend"
command: |
yarn install
yarn run fmt:clj:check
- run:
name: "exporter fmt check"
working_directory: "./exporter"
command: |
yarn install
yarn run fmt:clj:check
- run:
name: "common fmt check"
working_directory: "./common"
command: |
yarn install
yarn run fmt:clj:check
- run:
name: "frontend fmt check"
working_directory: "./frontend"
command: |
yarn install
yarn run fmt:clj:check
- run:
name: "common linter check"
name: "prepopulate linter cache"
working_directory: "./common"
command: |
yarn install
yarn run lint:clj
- run:
name: "frontend linter check"
working_directory: "./frontend"
command: |
yarn install
yarn run lint:scss
yarn run lint:clj
- run:
name: "backend linter check"
name: "fmt check & linter"
working_directory: "./backend"
command: |
yarn install
yarn run fmt:clj:check
yarn run lint:clj
- run:
name: "exporter linter check"
working_directory: "./exporter"
command: |
yarn install
yarn run lint:clj
- run:
name: "common tests"
working_directory: "./common"
command: |
yarn test
clojure -M:dev:test
- run:
name: "frontend tests"
working_directory: "./frontend"
command: |
yarn install
yarn test
- run:
name: "frontend integration tests"
working_directory: "./frontend"
command: |
yarn install
yarn run compile
clojure -M:dev:shadow-cljs release main
yarn playwright install --with-deps chromium
yarn e2e:test
- run:
name: "backend tests"
name: "tests"
working_directory: "./backend"
command: |
clojure -M:dev:test
clojure -M:dev:test --reporter kaocha.report/documentation
environment:
PENPOT_TEST_DATABASE_URI: "postgresql://localhost/penpot_test"
@@ -125,7 +170,45 @@ jobs:
PENPOT_TEST_REDIS_URI: "redis://localhost/1"
- save_cache:
paths:
- ~/.m2
key: v1-dependencies-{{ checksum "backend/deps.edn" }}-{{ checksum "frontend/deps.edn"}}-{{ checksum "common/deps.edn"}}
paths:
- ~/.m2
key: v1-dependencies-{{ checksum "backend/deps.edn" }}
test-exporter:
docker:
- image: penpotapp/devenv:latest
working_directory: ~/repo
resource_class: medium+
environment:
JAVA_OPTS: -Xmx4g -Xms100m -XX:+UseSerialGC
NODE_OPTIONS: --max-old-space-size=4096
steps:
- checkout
- run:
name: "prepopulate linter cache"
working_directory: "./common"
command: |
yarn install
yarn run lint:clj
- run:
name: "fmt check & linter"
working_directory: "./exporter"
command: |
yarn install
yarn run fmt:clj:check
yarn run lint:clj
workflows:
penpot:
jobs:
- test-frontend
- test-integration
- test-backend
- test-common
- test-exporter

View File

@@ -3,7 +3,6 @@
promesa.core/->> clojure.core/->>
promesa.core/-> clojure.core/->
promesa.exec.csp/go-loop clojure.core/loop
rumext.v2/defc clojure.core/defn
promesa.util/with-open clojure.core/with-open
app.common.schema.generators/let clojure.core/let
app.common.data/export clojure.core/def
@@ -20,6 +19,7 @@
app.db/with-atomic hooks.export/penpot-with-atomic
potok.v2.core/reify hooks.export/potok-reify
rumext.v2/fnc hooks.export/rumext-fnc
rumext.v2/defc hooks.export/rumext-defc
rumext.v2/lazy-component hooks.export/rumext-lazycomponent
shadow.lazy/loadable hooks.export/rumext-lazycomponent
}}

View File

@@ -67,12 +67,86 @@
(let [[cname mdata params & body] (rest (:children node))
[params body] (if (api/vector-node? mdata)
[mdata (cons params body)]
[params body])]
(let [result (api/list-node
(into [(api/token-node 'fn)
params]
(cons mdata body)))]
{:node result})))
[params body])
result (api/list-node
(into [(api/token-node 'fn) params]
(cons mdata body)))]
{:node result}))
(defn- parse-defc
[{:keys [children] :as node}]
(let [args (rest children)
[cname args]
(if (api/token-node? (first args))
[(first args) (rest args)]
(throw (ex-info "unexpected1" {})))
[docs args]
(if (api/string-node? (first args))
[(first args) (rest args)]
["" args])
[mdata args]
(if (api/map-node? (first args))
[(first args) (rest args)]
[(api/map-node []) args])
[params body]
(if (api/vector-node? (first args))
[(first args) (rest args)]
(throw (ex-info "unexpected2" {})))]
[cname docs mdata params body]))
(defn rumext-defc
[{:keys [node]}]
(let [[cname docs mdata params body] (parse-defc node)
param1 (first (:children params))
paramN (rest (:children params))
param1 (if (api/map-node? param1)
(let [param1 (into {} (comp
(partition-all 2)
(map (fn [[k v]]
[(if (api/keyword-node? k)
(:k k)
k)
(if (api/vector-node? v)
(vec (:children v))
v)])))
(:children param1))
binding (:rest param1)
param1 (if binding
(if (contains? param1 :as)
(update param1 :keys (fnil conj []) binding)
(assoc param1 :as binding))
param1)]
(->> (dissoc param1 :rest)
(mapcat (fn [[k v]]
[(if (keyword? k)
(api/keyword-node k)
k)
(if (vector? v)
(api/vector-node v)
v)]))
(api/map-node)))
param1)
result (api/list-node
(into [(api/token-node 'defn)
cname
(api/vector-node (filter some? (cons param1 paramN)))]
(cons mdata body)))]
;; (prn (api/sexpr result))
{:node result}))
(defn rumext-lazycomponent

5
.gitignore vendored
View File

@@ -48,6 +48,8 @@
/deploy
/docker/images/bundle*
/exporter/target
/frontend/.storybook/preview-body.html
/frontend/.storybook/preview-head.html
/frontend/cypress/fixtures/validuser.json
/frontend/cypress/videos/*/
/frontend/cypress/videos/*/
@@ -68,8 +70,9 @@
/web
clj-profiler/
node_modules
frontend/.storybook/preview-body.html
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/render-wasm/target/
/**/.yarn/*

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
v20.11.1

View File

@@ -1,5 +1,242 @@
# CHANGELOG
## 2.5.0
### :rocket: Epics and highlights
### :boom: Breaking changes & Deprecations
### :heart: Community contributions (Thank you!)
### :sparkles: New features
### :bug: Bugs fixed
## 2.4.0
### :rocket: Epics and highlights
### :boom: Breaking changes & Deprecations
- Use [nginx-unprivileged](https://hub.docker.com/r/nginxinc/nginx-unprivileged) as base image for
Penpot's frontend docker image. Now all the docker images runs with the same unprivileged user
(penpot). Because of that, the default NGINX listen port is now 8080 instead of 80, so
you will have to modify your infrastructure to apply this change.
- Redis 7.2 is explicitly pinned in our example docker-compose.yml file. This is done because,
starting with the next versions, Redis is no longer distributed under an open-source license.
On-premise users are obviously free to upgrade to the version they are using or a more modern one.
Keep in mind that if you were using a version other than 7.2, you may have to recreate the volume
associated with the Redis container because the 7.2 storage format may not be compatible with what
you already have stored on the volume, and Redis may not start. In the near future, we will evaluate
whether to move to an open-source version of Redis (such as https://valkey.io/).
### :heart: Community contributions (Thank you!)
### :sparkles: New features
- Viewer role for team members [Taiga #1056 & #6590](https://tree.taiga.io/project/penpot/us/1056 & https://tree.taiga.io/project/penpot/us/6590)
- File history versions management [Taiga](https://tree.taiga.io/project/penpot/us/187?milestone=411120)
- Rename selected layer via keyboard shortcut and context menu option [Taiga #8882](https://tree.taiga.io/project/penpot/us/8882)
### :bug: Bugs fixed
## 2.3.3
### :bug: Bugs fixed
- Fix problem creating manual overlay interactions [Taiga #9146](https://tree.taiga.io/project/penpot/issue/9146)
## 2.3.2
### :bug: Bugs fixed
- Fix null pointer exception on number checking functions
- Fix problem with grid layout ordering after moving [Taiga #9179](https://tree.taiga.io/project/penpot/issue/9179)
### :books: Documentation
- Add initial documentation for Kubernetes
## 2.3.1
### :bug: Bugs fixed
- Fix unexpected issue on interaction between plugins sandbox and
internal impl of promise
## 2.3.0
### :rocket: Epics and highlights
- **New plugin system.**
Penpot now supports custom plugins. Read everything about developing your plugins [HERE](https://help.penpot.app/plugins/)
### :boom: Breaking changes & Deprecations
### :heart: Community contributions (Thank you!)
- All our plugins beta testers :heart:.
- Fix problem when translating multiple path points by @eeropic [#4459](https://github.com/penpot/penpot/issues/4459)
### :sparkles: New features
- **Replace Draft.js completely with a custom editor** [Taiga #7706](https://tree.taiga.io/project/penpot/us/7706)
This refactor adds better IME support, more performant text editing
experience and a better clipboard support while keeping full
retrocompatibility with previous editor.
You can enable it with the `enable-feature-text-editor-v2` configuration flag.
### :bug: Bugs fixed
- Fix problem with constraints buttons [Taiga #8465](https://tree.taiga.io/project/penpot/issue/8465)
- Fix problem with go back button on error page [Taiga #8887](https://tree.taiga.io/project/penpot/issue/8887)
- Fix problem with shadows in text for Safari [Taiga #8770](https://tree.taiga.io/project/penpot/issue/8770)
- Fix a regression with feedback form subject and content limits [Taiga #8908](https://tree.taiga.io/project/penpot/issue/8908)
- Fix problem with stroke and filter ordering in frames [Github #5058](https://github.com/penpot/penpot/issues/5058)
- Fix problem with hover layers when hidden/blocked [Github #5074](https://github.com/penpot/penpot/issues/5074)
- Fix problem with precision on boolean calculation [Taiga #8482](https://tree.taiga.io/project/penpot/issue/8482)
- Fix problem when translating multiple path points [Github #4459](https://github.com/penpot/penpot/issues/4459)
- Fix problem on importing (and exporting) files with flows [Taiga #8914](https://tree.taiga.io/project/penpot/issue/8914)
- Fix Internal Error page: "go to your penpot" wrong design [Taiga #8922](https://tree.taiga.io/project/penpot/issue/8922)
- Fix problem updating layout when toggle visibility in component copy [Github #5143](https://github.com/penpot/penpot/issues/5143)
- Fix "Done" button on toolbar on inspect mode should go to design mode [Taiga #8933](https://tree.taiga.io/project/penpot/issue/8933)
- Fix problem with shortcuts in text editor [Github #5078](https://github.com/penpot/penpot/issues/5078)
- Fix problems with show in viewer and interactions [Github #4868](https://github.com/penpot/penpot/issues/4868)
- Add visual feedback when moving an element into a board [Github #3210](https://github.com/penpot/penpot/issues/3210)
- Fix percent calculation on grid layout tracks [Github #4688](https://github.com/penpot/penpot/issues/4688)
- Fix problem with caps and inner shadows [Github #4517](https://github.com/penpot/penpot/issues/4517)
- Fix problem with horizontal/vertical lines and shadows [Github #4516](https://github.com/penpot/penpot/issues/4516)
- Fix problem with layers overflowing panel [Taiga #9021](https://tree.taiga.io/project/penpot/issue/9021)
- Fix in workspace you can manage rulers on view mode [Taiga #8966](https://tree.taiga.io/project/penpot/issue/8966)
- Fix problem with swap components in grid layout [Taiga #9066](https://tree.taiga.io/project/penpot/issue/9066)
## 2.2.1
### :bug: Bugs fixed
- Fix problem with Ctrl+F shortcut on the dashboard [Taiga #8876](https://tree.taiga.io/project/penpot/issue/8876)
- Fix visual problem with the font-size dropdown in assets [Taiga #8872](https://tree.taiga.io/project/penpot/issue/8872)
- Add limits for invitation RPC methods (hard limit 25 emails per request)
## 2.2.0
### :rocket: Epics and highlights
### :boom: Breaking changes & Deprecations
- Removed "merge assets" option when exporting ".svg + .json" files. After the components changes the option wasn't
working properly and we're planning to change the format soon. We think it's better to deprecate the option for the
time being.
### :heart: Community contributions (Thank you!)
- Set proper default tenant on exporter (by @june128) [#4946](https://github.com/penpot/penpot/pull/4946)
- Correct a spelling in onboarding.edn (by @n-stha) [#4936](https://github.com/penpot/penpot/pull/4936)
### :sparkles: New features
- **Tiered File Data Storage** [Taiga #8376](https://tree.taiga.io/project/penpot/us/8376)
This feature allows offloading file data that is not actively used
from the database to object storage (e.g., filesystem, S3), thereby
freeing up space in the database. It can be enabled with the
`enable-enable-tiered-file-data-storage` flag.
*(On-Premise feature, EXPERIMENTAL).*
- **JSON Interoperability for HTTP API** [Taiga #8372](https://tree.taiga.io/project/penpot/us/8372)
Enables full JSON interoperability for our HTTP API. Previously,
JSON was only barely supported for output when the
`application/json` media type was specified in the `Accept` header,
or when `_fmt=json` was passed as a query parameter. With this
update, we now offer proper bi-directional support for using our API
with plain JSON, instead of Transit.
- **Automatic File Snapshotting**
Adds the ability to automatically take and maintain a limited set of
snapshots of active files without explicit user intervention. This
feature allows on-premise administrators to recover the state of a
file from a past point in time in a limited manner.
It can be enabled with the `enable-auto-file-snapshot` flag and
configured with the following settings:
```bash
# Take snapshots every 10 update operations
PENPOT_AUTO_FILE_SNAPSHOT_EVERY=10
# Take a snapshot if it has been more than 3 hours since the file was last modified
PENPOT_AUTO_FILE_SNAPSHOT_TIMEOUT=3h
# The total number of snapshots to keep
PENPOT_AUTO_FILE_SNAPSHOT_TOTAL=10
```
Snapshots are only taken during update operations; there is NO
active background process for this.
- Add separated flag `enable-oidc-registration` for enable the
registration only for OIDC authentication backend [Github
#4882](https://github.com/penpot/penpot/issues/4882)
- Update templates in libraries & templates in dashboard modal [Taiga #8145](https://tree.taiga.io/project/penpot/us/8145)
- **Design System**
We implemented and subbed in new components from our Design System: `loader*` ([Taiga #8355](https://tree.taiga.io/project/penpot/task/8355)) and `tab-switcher*` ([Taiga #8518](https://tree.taiga.io/project/penpot/task/8518)).
- **Storybook** [Taiga #6329](https://tree.taiga.io/project/penpot/us/6329)
The Design System components are now published in a Storybook, available at `/storybook`.
### :bug: Bugs fixed
- Fix webhook checkbox position [Taiga #8634](https://tree.taiga.io/project/penpot/issue/8634)
- Fix wrong props on padding input [Taiga #8254](https://tree.taiga.io/project/penpot/issue/8254)
- Fix fill collapsed options [Taiga #8351](https://tree.taiga.io/project/penpot/issue/8351)
- Fix scroll on color picker modal [Taiga #8353](https://tree.taiga.io/project/penpot/issue/8353)
- Fix components are not dragged from the group to the assets tab [Taiga #8273](https://tree.taiga.io/project/penpot/issue/8273)
- Fix problem with SVG import [Github #4888](https://github.com/penpot/penpot/issues/4888)
- Fix problem with overlay positions in viewer [Taiga #8464](https://tree.taiga.io/project/penpot/issue/8464)
- Fix layer panel overflowing [Taiga #8665](https://tree.taiga.io/project/penpot/issue/8665)
- Fix problem when creating a component instance from grid layout [Github #4881](https://github.com/penpot/penpot/issues/4881)
- Fix problem when dismissing shared library update [Taiga #8669](https://tree.taiga.io/project/penpot/issue/8669)
- Fix visual problem with stroke cap menu [Taiga #8730](https://tree.taiga.io/project/penpot/issue/8730)
- Fix issue when exporting libraries when merging libraries [Taiga #8758](https://tree.taiga.io/project/penpot/issue/8758)
- Fix problem with comments max length [Taiga #8778](https://tree.taiga.io/project/penpot/issue/8778)
- Fix copy/paste images in Safari [Taiga #8771](https://tree.taiga.io/project/penpot/issue/8771)
- Fix swap when the copy is the only child of a group [#5075](https://github.com/penpot/penpot/issues/5075)
- Fix file builder hangs when exporting [#5099](https://github.com/penpot/penpot/issues/5099)
## 2.1.5
### :bug: Bugs fixed
- Fix broken webhooks [Taiga #8370](https://tree.taiga.io/project/penpot/issue/8370)
## 2.1.4
### :bug: Bugs fixed
- Fix json encoding on zip encoding decoding.
- Add schema validation for color changes.
- Fix render of some texts without position data.
## 2.1.3
- Don't allow registration when registration is disabled and invitation token is used [Github #4975](https://github.com/penpot/penpot/issues/4975)
## 2.1.2
### :bug: Bugs fixed
@@ -27,7 +264,7 @@
### :boom: Breaking changes & Deprecations
### :heart: Community contributions (Thank you!)
### :heart: Communityq contributions (Thank you!)
### :sparkles: New features

View File

@@ -48,7 +48,7 @@ quick win.
If is going to be your first pull request, You can learn how from this
free video series:
https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github
https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github
We will use the `easy fix` mark for tag for indicate issues that are
easy for beginners.

View File

@@ -8,10 +8,12 @@
<img alt="penpot header image" src="https://penpot.app/images/readme/github-light-mode.png">
</picture>
<p align="center"><a href="https://www.mozilla.org/en-US/MPL/2.0" rel="nofollow"><img src="https://camo.githubusercontent.com/3fcf3d6b678ea15fde3cf7d6af0e242160366282d62a7c182d83a50bfee3f45e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d504c2d322e302d626c75652e737667" alt="License: MPL-2.0" data-canonical-src="https://img.shields.io/badge/MPL-2.0-blue.svg" style="max-width:100%;"></a>
<a href="https://gitter.im/penpot/community" rel="nofollow"><img src="https://camo.githubusercontent.com/5b0aecb33434f82a7b158eab7247544235ada0cf7eeb9ce8e52562dd67f614b7/68747470733a2f2f6261646765732e6769747465722e696d2f736572656e6f2d78797a2f636f6d6d756e6974792e737667" alt="Gitter" data-canonical-src="https://badges.gitter.im/sereno-xyz/community.svg" style="max-width:100%;"></a>
<a href="https://tree.taiga.io/project/penpot/" title="Managed with Taiga.io" rel="nofollow"><img src="https://camo.githubusercontent.com/4a1d1112f0272e3393b1e8da312ff4435418e9e2eb4c0964881e3680f90a653c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d616e61676564253230776974682d54414947412e696f2d3730396631342e737667" alt="Managed with Taiga.io" data-canonical-src="https://img.shields.io/badge/managed%20with-TAIGA.io-709f14.svg" style="max-width:100%;"></a>
<a href="https://gitpod.io/#https://github.com/penpot/penpot" rel="nofollow"><img src="https://camo.githubusercontent.com/daadb4894128d1e19b72d80236f5959f1f2b47f9fe081373f3246131f0189f6c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f476974706f642d72656164792d2d746f2d2d636f64652d626c75653f6c6f676f3d676974706f64" alt="Gitpod ready-to-code" data-canonical-src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod" style="max-width:100%;"></a></p>
<p align="center">
<a href="https://www.mozilla.org/en-US/MPL/2.0" rel="nofollow"><img alt="License: MPL-2.0" src="https://img.shields.io/badge/MPL-2.0-blue.svg" style="max-width:100%;"></a>
<a href="https://community.penpot.app" rel="nofollow"><img alt="Penpot Community" src="https://img.shields.io/discourse/posts?server=https%3A%2F%2Fcommunity.penpot.app" style="max-width:100%;"></a>
<a href="https://tree.taiga.io/project/penpot/" title="Managed with Taiga.io" rel="nofollow"><img alt="Managed with Taiga.io" src="https://img.shields.io/badge/managed%20with-TAIGA.io-709f14.svg" style="max-width:100%;"></a>
<a href="https://gitpod.io/#https://github.com/penpot/penpot" rel="nofollow"><img alt="Gitpod ready-to-code" src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod" style="max-width:100%;"></a>
</p>
<p align="center">
<a href="https://penpot.app/"><b>Website</b></a> •
@@ -50,6 +52,7 @@ Penpots latest [huge release 2.0](https://penpot.app/dev-diaries), takes the
- [Why Penpot](#why-penpot)
- [Getting Started](#getting-started)
- [Community](#community)
- [Contributing](#contributing)
- [Resources](#resources)
- [License](#license)
@@ -57,6 +60,9 @@ Penpots latest [huge release 2.0](https://penpot.app/dev-diaries), takes the
Penpot expresses designs as code. Designers can do their best work and see it will be beautifully implemented by developers in a two-way collaboration.
### Plugin system ###
[Penpot plugins](https://penpot.app/penpothub/plugins) let you expand the platform's capabilities, give you the flexibility to integrate it with other apps, and design custom solutions.
### Designed for developers ###
Penpot was built to serve both designers and developers and create a fluid design-code process. You have the choice to enjoy real-time collaboration or play "solo".

View File

@@ -3,10 +3,10 @@
:deps
{penpot/common {:local/root "../common"}
org.clojure/clojure {:mvn/version "1.12.0-alpha12"}
org.clojure/clojure {:mvn/version "1.12.0"}
org.clojure/tools.namespace {:mvn/version "1.5.0"}
com.github.luben/zstd-jni {:mvn/version "1.5.6-3"}
com.github.luben/zstd-jni {:mvn/version "1.5.6-6"}
io.prometheus/simpleclient {:mvn/version "0.16.0"}
io.prometheus/simpleclient_hotspot {:mvn/version "0.16.0"}
@@ -17,33 +17,33 @@
io.prometheus/simpleclient_httpserver {:mvn/version "0.16.0"}
io.lettuce/lettuce-core {:mvn/version "6.3.2.RELEASE"}
io.lettuce/lettuce-core {:mvn/version "6.4.0.RELEASE"}
java-http-clj/java-http-clj {:mvn/version "0.4.3"}
funcool/yetti
{:git/tag "v10.0"
:git/sha "520613f"
{:git/tag "v11.4"
:git/sha "ce50d42"
:git/url "https://github.com/funcool/yetti.git"
:exclusions [org.slf4j/slf4j-api]}
com.github.seancorfield/next.jdbc {:mvn/version "1.3.939"}
metosin/reitit-core {:mvn/version "0.7.0"}
nrepl/nrepl {:mvn/version "1.1.2"}
cider/cider-nrepl {:mvn/version "0.48.0"}
com.github.seancorfield/next.jdbc {:mvn/version "1.3.955"}
metosin/reitit-core {:mvn/version "0.7.2"}
nrepl/nrepl {:mvn/version "1.3.0"}
cider/cider-nrepl {:mvn/version "0.50.2"}
org.postgresql/postgresql {:mvn/version "42.7.3"}
org.xerial/sqlite-jdbc {:mvn/version "3.46.0.0"}
org.postgresql/postgresql {:mvn/version "42.7.4"}
org.xerial/sqlite-jdbc {:mvn/version "3.46.1.3"}
com.zaxxer/HikariCP {:mvn/version "5.1.0"}
com.zaxxer/HikariCP {:mvn/version "6.0.0"}
io.whitfin/siphash {:mvn/version "2.0.0"}
buddy/buddy-hashers {:mvn/version "2.0.167"}
buddy/buddy-sign {:mvn/version "3.5.351"}
buddy/buddy-sign {:mvn/version "3.6.1-359"}
com.github.ben-manes.caffeine/caffeine {:mvn/version "3.1.8"}
org.jsoup/jsoup {:mvn/version "1.17.2"}
org.jsoup/jsoup {:mvn/version "1.18.1"}
org.im4java/im4java
{:git/tag "1.4.0-penpot-2"
:git/sha "e2b3e16"
@@ -58,7 +58,7 @@
;; Pretty Print specs
pretty-spec/pretty-spec {:mvn/version "0.1.4"}
software.amazon.awssdk/s3 {:mvn/version "2.25.63"}
software.amazon.awssdk/s3 {:mvn/version "2.28.26"}
}
:paths ["src" "resources" "target/classes"]
@@ -74,7 +74,7 @@
:build
{:extra-deps
{io.github.clojure/tools.build {:git/tag "v0.10.3" :git/sha "15ead66"}}
{io.github.clojure/tools.build {:git/tag "v0.10.5" :git/sha "2a21b7a"}}
:ns-default build}
:test

View File

@@ -20,6 +20,7 @@
[app.common.schema.desc-native :as smdn]
[app.common.schema.generators :as sg]
[app.common.spec :as us]
[app.common.json :as json]
[app.common.transit :as t]
[app.common.types.file :as ctf]
[app.common.uuid :as uuid]
@@ -29,7 +30,6 @@
[app.srepl.helpers :as srepl.helpers]
[app.srepl.main :as srepl]
[app.util.blob :as blob]
[app.util.json :as json]
[app.util.time :as dt]
[clj-async-profiler.core :as prof]
[clojure.contrib.humanize :as hum]
@@ -137,7 +137,6 @@
;; :v6 v6
;; }])))
(defn calculate-frames
[{:keys [data]}]
(->> (vals (:pages-index data))

View File

@@ -4,7 +4,7 @@
"license": "MPL-2.0",
"author": "Kaleidos INC",
"private": true,
"packageManager": "yarn@4.2.2",
"packageManager": "yarn@4.3.1",
"repository": {
"type": "git",
"url": "https://github.com/penpot/penpot"

View File

@@ -1,5 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title>
@@ -110,15 +111,20 @@
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:97px;">
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png" style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;" width="97" />
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
width="97" />
</td>
</tr>
</tbody>
@@ -151,7 +157,8 @@
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
@@ -164,29 +171,43 @@
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">Hello {{name|abbreviate:25}}!</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
Hello {{name|abbreviate:25}}!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">We received a request to change your current email to {{ pending-email }}.</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
We received a request to change your current email to {{ pending-email }}.</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">Click to the link below to confirm the change:</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
Click to the link below to confirm the change:</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;">
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%;">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation" style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;" valign="middle">
<a href="{{ public-uri }}/#/auth/verify-token?token={{token}}" style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;" target="_blank"> Confirm email change </a>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/auth/verify-token?token={{token}}"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Confirm email change </a>
</td>
</tr>
</table>
@@ -194,17 +215,24 @@
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">If you received this email by mistake, please consider changing your password for security reasons.</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
If you received this email by mistake, please consider changing your password for security
reasons.</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">Enjoy!</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
Enjoy!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">The Penpot team.</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
The Penpot team.</div>
</td>
</tr>
</table>
@@ -221,258 +249,10 @@
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:24px 0 0 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
{% include "app/email/includes/footer.html" %}
<tr>
<td
class="" style="vertical-align:top;width:425px;"
>
<![endif]-->
<div class="mj-column-px-425 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">Penpot is the first Open Source design and prototyping platform meant for cross-domain teams.</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
>
<tr>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://penpot.app/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-uxbox.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://twitter.com/penpotapp" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-twitter.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://github.com/penpot/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-github.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://www.instagram.com/penpot.app/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-instagram.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://tree.taiga.io/project/penpot" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-taiga.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0 0 24px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">Penpot | Made with &lt;3 and Open Source</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</div>
</body>
</html>
</html>

View File

@@ -0,0 +1,323 @@
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:24px 0 0 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:425px;"
>
<![endif]-->
<div class="mj-column-px-425 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">
Penpot is the first Open Source design and prototyping platform meant for
cross-domain teams.
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
>
<tr>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-radius:3px;width:24px;">
<tr>
<td
style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://penpot.app/" target="_blank">
<img height="24"
src="{{ public-uri }}/images/email/logo-uxbox.png"
style="border-radius:3px;display:block;"
width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-radius:3px;width:24px;">
<tr>
<td
style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://x.com/penpotapp" target="_blank">
<img height="24"
src="{{ public-uri }}/images/email/logo-x.png"
style="border-radius:3px;display:block;"
width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-radius:3px;width:24px;">
<tr>
<td
style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://github.com/penpot/" target="_blank">
<img height="24"
src="{{ public-uri }}/images/email/logo-github.png"
style="border-radius:3px;display:block;"
width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-radius:3px;width:24px;">
<tr>
<td
style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://www.linkedin.com/company/penpotdesign/"
target="_blank">
<img height="24"
src="{{ public-uri }}/images/email/logo-linkedin.png"
style="border-radius:3px;display:block;"
width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-radius:3px;width:24px;">
<tr>
<td
style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://fosstodon.org/@penpot/" target="_blank">
<img height="24"
src="{{ public-uri }}/images/email/logo-mastodon.png"
style="border-radius:3px;display:block;"
width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-radius:3px;width:24px;">
<tr>
<td
style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://tree.taiga.io/project/penpot"
target="_blank">
<img height="24"
src="{{ public-uri }}/images/email/logo-taiga.png"
style="border-radius:3px;display:block;"
width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0 0 24px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">
Penpot | Made with &lt;3 and Open Source</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->

View File

@@ -1,5 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title>
@@ -110,15 +111,20 @@
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:97px;">
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png" style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;" width="97" />
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
width="97" />
</td>
</tr>
</tbody>
@@ -151,7 +157,8 @@
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
@@ -164,24 +171,36 @@
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">Hello!</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
Hello!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">{{invited-by|abbreviate:25}} has invited you to join the team “{{ team|abbreviate:25 }}”.</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
{{invited-by|abbreviate:25}} has invited you to join the team “{{ team|abbreviate:25 }}”.</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;">
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%;">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation" style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;" valign="middle">
<a href="{{ public-uri }}/#/auth/verify-token?token={{token}}" style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;" target="_blank"> Accept invite </a>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/auth/verify-token?token={{token}}"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Accept invite </a>
</td>
</tr>
</table>
@@ -189,12 +208,16 @@
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">Enjoy!</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
Enjoy!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">The Penpot team.</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
The Penpot team.</div>
</td>
</tr>
</table>
@@ -211,258 +234,10 @@
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:24px 0 0 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
{% include "app/email/includes/footer.html" %}
<tr>
<td
class="" style="vertical-align:top;width:425px;"
>
<![endif]-->
<div class="mj-column-px-425 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">Penpot is the first Open Source design and prototyping platform meant for cross-domain teams.</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
>
<tr>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://penpot.app/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-uxbox.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://twitter.com/penpotapp" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-twitter.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://github.com/penpot/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-github.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://www.instagram.com/penpot.app/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-instagram.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://tree.taiga.io/project/penpot" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-taiga.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0 0 24px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">Penpot | Made with &lt;3 and Open Source</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</div>
</body>
</html>
</html>

View File

@@ -0,0 +1,244 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title>
</title>
<!--[if !mso]><!-- -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#outlook a {
padding: 0;
}
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
p {
display: block;
margin: 13px 0;
}
</style>
<!--[if mso]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
<!--[if !mso]><!-->
<link href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro" rel="stylesheet" type="text/css">
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Source%20Sans%20Pro);
</style>
<!--<![endif]-->
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-100 {
width: 100% !important;
max-width: 100%;
}
.mj-column-px-425 {
width: 425px !important;
max-width: 425px;
}
}
</style>
<style type="text/css">
@media only screen and (max-width:480px) {
table.mj-full-width-mobile {
width: 100% !important;
}
td.mj-full-width-mobile {
width: auto !important;
}
}
</style>
</head>
<body style="background-color:#E5E5E5;">
<div style="background-color:#E5E5E5;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:97px;">
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
width="97" />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
Hello!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
As you requested, {{invited-by|abbreviate:25}} has added you to the team “{{
team|abbreviate:25}}”.</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%;">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/dashboard/team/{{team-id}}/projects"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Go to the Team </a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
Enjoy!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
The Penpot team.</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
{% include "app/email/includes/footer.html" %}
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
You have joined {{team}}

View File

@@ -0,0 +1,10 @@
Hello!
As you requested, {{invited-by|abbreviate:25}} has added you to the team “{{ team|abbreviate:25}}”.
Go to the team with this link:
{{ public-uri }}/#/dashboard/team/{{team-id}}
Enjoy!
The Penpot team.

View File

@@ -1,5 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title>
@@ -110,15 +111,20 @@
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:97px;">
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png" style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;" width="97" />
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
width="97" />
</td>
</tr>
</tbody>
@@ -151,7 +157,8 @@
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
@@ -164,24 +171,37 @@
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">Hello {{name|abbreviate:25}}!</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
Hello {{name|abbreviate:25}}!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">We have received a request to reset your password. Click the link below to choose a new one:</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
We have received a request to reset your password. Click the link below to choose a new one:
</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;">
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%;">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation" style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;" valign="middle">
<a href="{{ public-uri }}/#/auth/recovery?token={{token}}" style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;" target="_blank"> Reset password </a>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/auth/recovery?token={{token}}"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Reset password </a>
</td>
</tr>
</table>
@@ -189,17 +209,24 @@
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">If you received this email by mistake, you can safely ignore it. Your password won't be changed.</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
If you received this email by mistake, you can safely ignore it. Your password won't be changed.
</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">Enjoy!</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
Enjoy!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">The Penpot team.</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
The Penpot team.</div>
</td>
</tr>
</table>
@@ -216,258 +243,10 @@
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:24px 0 0 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
{% include "app/email/includes/footer.html" %}
<tr>
<td
class="" style="vertical-align:top;width:425px;"
>
<![endif]-->
<div class="mj-column-px-425 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">Penpot is the first Open Source design and prototyping platform meant for cross-domain teams.</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
>
<tr>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://penpot.app/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-uxbox.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://twitter.com/penpotapp" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-twitter.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://github.com/penpot/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-github.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://www.instagram.com/penpot.app/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-instagram.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://tree.taiga.io/project/penpot" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-taiga.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0 0 24px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">Penpot | Made with &lt;3 and Open Source</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</div>
</body>
</html>
</html>

View File

@@ -1,5 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title>
@@ -110,15 +111,20 @@
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:97px;">
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png" style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;" width="97" />
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
width="97" />
</td>
</tr>
</tbody>
@@ -151,7 +157,8 @@
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
@@ -164,24 +171,37 @@
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">Hello {{name|abbreviate:25}}!</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
Hello {{name|abbreviate:25}}!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">Thanks for signing up for your Penpot account! Please verify your email using the link below and get started building mockups and prototypes today!</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
Thanks for signing up for your Penpot account! Please verify your email using the link below and
get started building mockups and prototypes today!</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;">
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%;">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation" style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;" valign="middle">
<a href="{{ public-uri }}/#/auth/verify-token?token={{token}}" style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;" target="_blank"> Verify email </a>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/auth/verify-token?token={{token}}"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Verify email </a>
</td>
</tr>
</table>
@@ -189,12 +209,16 @@
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">Enjoy!</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
Enjoy!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">The Penpot team.</div>
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
The Penpot team.</div>
</td>
</tr>
</table>
@@ -211,258 +235,10 @@
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:24px 0 0 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
{% include "app/email/includes/footer.html" %}
<tr>
<td
class="" style="vertical-align:top;width:425px;"
>
<![endif]-->
<div class="mj-column-px-425 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">Penpot is the first Open Source design and prototyping platform meant for cross-domain teams.</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
>
<tr>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://penpot.app/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-uxbox.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://twitter.com/penpotapp" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-twitter.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://github.com/penpot/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-github.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://www.instagram.com/penpot.app/" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-instagram.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
<td>
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
<tr>
<td style="padding:0 8px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:24px;">
<tr>
<td style="font-size:0;height:24px;vertical-align:middle;width:24px;">
<a href="https://tree.taiga.io/project/penpot" target="_blank">
<img height="24" src="{{ public-uri }}/images/email/logo-taiga.png" style="border-radius:3px;display:block;" width="24" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0 0 24px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Source Sans Pro, sans-serif;font-size:14px;line-height:150%;text-align:center;color:#64666A;">Penpot | Made with &lt;3 and Open Source</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</div>
</body>
</html>
</html>

View File

@@ -0,0 +1,254 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title>
</title>
<!--[if !mso]><!-- -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#outlook a {
padding: 0;
}
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
p {
display: block;
margin: 13px 0;
}
</style>
<!--[if mso]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
<!--[if !mso]><!-->
<link href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro" rel="stylesheet" type="text/css">
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Source%20Sans%20Pro);
</style>
<!--<![endif]-->
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-100 {
width: 100% !important;
max-width: 100%;
}
.mj-column-px-425 {
width: 425px !important;
max-width: 425px;
}
}
</style>
<style type="text/css">
@media only screen and (max-width:480px) {
table.mj-full-width-mobile {
width: 100% !important;
}
td.mj-full-width-mobile {
width: auto !important;
}
}
</style>
</head>
<body style="background-color:#E5E5E5;">
<div style="background-color:#E5E5E5;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:97px;">
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
width="97" />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
Hello!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<p>
{{requested-by|abbreviate:25}} ({{requested-by-email}}) wants to have view-only access to the
file named “{{file-name|abbreviate:25}}”.
</p>
<p>
Since this file is in your Penpot team, you can provide access by sending a view-only link.
This will allow {{requested-by|abbreviate:25}} to view the content without making any changes.
</p>
<p>To proceed, please click the button below to generate and send the view-only link:</p>
</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/view/{{file-id}}?page-id={{page-id}}&section=interactions&index=0&share=true"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Send a View-Only link </a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<p>If you do not wish to grant access at this time, you can simply disregard this email.</p>
<p>Thank you</p>
</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
The Penpot team.</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
{% include "app/email/includes/footer.html" %}
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
Request View-Only Access to “{{file-name|abbreviate:25}}”

View File

@@ -0,0 +1,17 @@
Hello!
{{requested-by|abbreviate:25}} ({{requested-by-email}}) wants to have view-only access to the file named “{{file-name|abbreviate:25}}”.
Since this file is in your Penpot team, you can provide access by sending a view-only link. This will allow {{requested-by|abbreviate:25}} to view the content without making any changes.
To proceed, please click the link below to generate and send the view-only link:
{{ public-uri }}/#/view/{{file-id}}?page-id={{page-id}}&section=interactions&index=0&share=true
If you do not wish to grant access at this time, you can simply disregard this email.
Thank you
The Penpot team.

View File

@@ -0,0 +1,277 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title>
</title>
<!--[if !mso]><!-- -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#outlook a {
padding: 0;
}
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
p {
display: block;
margin: 13px 0;
}
</style>
<!--[if mso]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
<!--[if !mso]><!-->
<link href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro" rel="stylesheet" type="text/css">
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Source%20Sans%20Pro);
</style>
<!--<![endif]-->
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-100 {
width: 100% !important;
max-width: 100%;
}
.mj-column-px-425 {
width: 425px !important;
max-width: 425px;
}
}
</style>
<style type="text/css">
@media only screen and (max-width:480px) {
table.mj-full-width-mobile {
width: 100% !important;
}
td.mj-full-width-mobile {
width: auto !important;
}
}
</style>
</head>
<body style="background-color:#E5E5E5;">
<div style="background-color:#E5E5E5;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:97px;">
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
width="97" />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
Hello!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<p>
{{requested-by|abbreviate:25}} ({{requested-by-email}}) has requested access to the file named
“{{file-name|abbreviate:25}}”.
</p>
<p>
Please note that the file is currently in Your Penpot 's team, so direct access cannot be
granted. However, you have two options to provide the requested access:
</p>
<ul>
<li>
<p>Move the File to Another Team:</p>
<p>You can move the file to another team and then give access to that team, inviting
{{requested-by|abbreviate:25}}.</p>
</li>
</ul>
</p>
</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<ul>
<li>
<p>Send a View-Only Link:</p>
<p>Alternatively, you can create and share a view-only link to the file. This will allow
{{requested-by|abbreviate:25}} to view the content without making any changes.</p>
<p>Click the button below to generate and send the link:</p>
</li>
</ul>
</p>
</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/view/{{file-id}}?page-id={{page-id}}&section=interactions&index=0&share=true"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Send a View-Only link </a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<p>If you do not wish to grant access at this time, you can simply disregard this email.</p>
<p>Thank you</p>
</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
The Penpot team.</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
{% include "app/email/includes/footer.html" %}
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
Request Access to “{{file-name|abbreviate:25}}”

View File

@@ -0,0 +1,30 @@
Hello!
Hello!
{{requested-by|abbreviate:25}} ({{requested-by-email}}) has requested access to the file named “{{file-name|abbreviate:25}}”.
Please note that the file is currently in Your Penpot 's team, so direct access cannot be granted. However, you have two options to provide the requested access:
- Move the File to Another Team:
You can move the file to another team and then give access to that team, inviting {{requested-by|abbreviate:25}}.
- Send a View-Only Link:
Alternatively, you can create and share a view-only link to the file. This will allow {{requested-by|abbreviate:25}} to view the content without making any changes.
Click the link below to generate and send the link:
{{ public-uri }}/#/view/{{file-id}}?page-id={{page-id}}&section=interactions&index=0&share=true
If you do not wish to grant access at this time, you can simply disregard this email.
Thank you
The Penpot team.

View File

@@ -0,0 +1,295 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title>
</title>
<!--[if !mso]><!-- -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#outlook a {
padding: 0;
}
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
p {
display: block;
margin: 13px 0;
}
</style>
<!--[if mso]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
<!--[if !mso]><!-->
<link href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro" rel="stylesheet" type="text/css">
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Source%20Sans%20Pro);
</style>
<!--<![endif]-->
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-100 {
width: 100% !important;
max-width: 100%;
}
.mj-column-px-425 {
width: 425px !important;
max-width: 425px;
}
}
</style>
<style type="text/css">
@media only screen and (max-width:480px) {
table.mj-full-width-mobile {
width: 100% !important;
}
td.mj-full-width-mobile {
width: auto !important;
}
}
</style>
</head>
<body style="background-color:#E5E5E5;">
<div style="background-color:#E5E5E5;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:97px;">
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
width="97" />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
Hello!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<p>
{{requested-by|abbreviate:25}} ({{requested-by-email}}) has requested access to the file named
“{{file-name|abbreviate:25}}”.
</p>
<p>
To provide this access, you have the following options:
</p>
<ul>
<li>
<p>Give Access to the “{{team-name|abbreviate:25}}” Team:</p>
<p>This will automatically include {{requested-by|abbreviate:25}} in the team, so the user
can see all the projects and files in it.</p>
<p>Click the button below to provide team access:</p>
</li>
</ul>
</p>
</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/dashboard/team/{{team-id}}/members?invite-email={{requested-by-email|urlescape }}"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Give access to “{{team-name|abbreviate:25}}” Team </a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<ul>
<li>
<p>Send a View-Only Link:</p>
<p>Alternatively, you can create and share a view-only link to the file. This will allow
{{requested-by|abbreviate:25}} to view the content without making any changes.</p>
<p>Click the button below to generate and send the link:</p>
</li>
</ul>
</p>
</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/view/{{file-id}}?page-id={{page-id}}&section=interactions&index=0&share=true"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Send a View-Only link </a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<p>If you do not wish to grant access at this time, you can simply disregard this email.</p>
<p>Thank you</p>
</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
The Penpot team.</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
{% include "app/email/includes/footer.html" %}
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
Request Access to “{{file-name|abbreviate:25}}”

View File

@@ -0,0 +1,34 @@
Hello!
Hello!
{{requested-by|abbreviate:25}} ({{requested-by-email}}) has requested access to the file named “{{file-name|abbreviate:25}}”.
To provide this access, you have the following options:
- Give Access to the “{{team-name|abbreviate:25}}” Team:
This will automatically include {{requested-by|abbreviate:25}} in the team, so the user can see all the projects and files in it.
Click the link below to provide team access:
{{ public-uri }}/#/dashboard/team/{{team-id}}/members?invite-email={{requested-by-email|urlescape}}
- Send a View-Only Link:
Alternatively, you can create and share a view-only link to the file. This will allow {{requested-by|abbreviate:25}} to view the content without making any changes.
Click the link below to generate and send the link:
{{ public-uri }}/#/view/{{file-id}}?page-id={{page-id}}&section=interactions&index=0&share=true
If you do not wish to grant access at this time, you can simply disregard this email.
Thank you
The Penpot team.

View File

@@ -0,0 +1,252 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title>
</title>
<!--[if !mso]><!-- -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#outlook a {
padding: 0;
}
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
p {
display: block;
margin: 13px 0;
}
</style>
<!--[if mso]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
<!--[if !mso]><!-->
<link href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro" rel="stylesheet" type="text/css">
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Source%20Sans%20Pro);
</style>
<!--<![endif]-->
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-100 {
width: 100% !important;
max-width: 100%;
}
.mj-column-px-425 {
width: 425px !important;
max-width: 425px;
}
}
</style>
<style type="text/css">
@media only screen and (max-width:480px) {
table.mj-full-width-mobile {
width: 100% !important;
}
td.mj-full-width-mobile {
width: auto !important;
}
}
</style>
</head>
<body style="background-color:#E5E5E5;">
<div style="background-color:#E5E5E5;">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:97px;">
<img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
width="97" />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix"
style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
width="100%">
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
Hello!</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<p>
{{requested-by|abbreviate:25}} ({{requested-by-email}}) wants to have access to the
“{{team-name|abbreviate:25}}” Team.
</p>
<p>
To provide access, please click the button below:
</p>
</div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle"
style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
style="border-collapse:separate;line-height:100%;">
<tr>
<td align="center" bgcolor="#31EFB8" role="presentation"
style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:#31EFB8;"
valign="middle">
<a href="{{ public-uri }}/#/dashboard/team/{{team-id}}/members?invite-email={{requested-by-email|urlescape}}"
style="display:inline-block;background:#31EFB8;color:#1F1F1F;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"
target="_blank"> Give access to “{{team-name|abbreviate:25}}” </a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
<p>If you do not wish to grant access at this time, you can simply disregard this email.</p>
<p>Thank you</p>
</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div
style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
The Penpot team.</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
{% include "app/email/includes/footer.html" %}
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
Request Access to “{{team-name|abbreviate:25}}”

View File

@@ -0,0 +1,14 @@
Hello!
{{requested-by|abbreviate:25}} ({{requested-by-email}}) wants to have access to the “{{team-name|abbreviate:25}}” Team.
To provide access, please click the link below:
{{ public-uri }}/#/dashboard/team/{{team-id}}/members?invite-email={{requested-by-email|urlescape}}
If you do not wish to grant access at this time, you can simply disregard this email.
Thank you
The Penpot team.

View File

@@ -1,39 +1,42 @@
[{:id "wireframing-kit"
:name "Wireframe library"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/wireframing-kit.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/Wireframing%20kit%20v1.1.penpot"}
{:id "prototype-examples"
:name "Prototipe template"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/prototype-examples.penpot"}
:name "Prototype template"
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/Prototype%20examples%20v1.1.penpot"}
{:id "plants-app"
:name "UI mockup example"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Plants-app.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/main/Plants-app.penpot"}
{:id "penpot-design-system"
:name "Design system example"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Penpot-Design-system.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/Penpot%20-%20Design%20System%20v2.1.penpot"}
{:id "tutorial-for-beginners"
:name "Tutorial for beginners"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/tutorial-for-beginners.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/main/tutorial-for-beginners.penpot"}
{:id "lucide-icons"
:name "Lucide Icons"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Lucide-icons.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/main/Lucide-icons.penpot"}
{:id "font-awesome"
:name "Font Awesome"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Font-Awesome.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/main/FontAwesome.penpot"}
{:id "black-white-mobile-templates"
:name "Black & White Mobile Templates"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Black-White-Mobile-Templates.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/main/Black-&-White-Mobile-Templates.penpot"}
{:id "avataaars"
:name "Avataaars"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Avataaars-by-Pablo-Stanley.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/main/Avataaars-by-Pablo-Stanley.penpot"}
{:id "ux-notes"
:name "UX Notes"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/UX-Notes.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/main/UX-Notes.penpot"}
{:id "whiteboarding-kit"
:name "Whiteboarding Kit"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Whiteboarding-mapping-kit.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/main/Whiteboarding-mapping-kit.penpot"}
{:id "open-color-scheme"
:name "Open Color Scheme"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Open-Color-Scheme.penpot"}
:file-uri "https://github.com/penpot/penpot-files/raw/main/Open%20Color%20Scheme%20(v1.9.1).penpot"}
{:id "flex-layout-playground"
:name "Flex Layout Playground"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Flex-Layout-Playground.penpot"}]
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/Flex%20Layout%20Playground%20v2.0.penpot"}
{:id "welcome"
:name "Welcome"
:file-uri "https://github.com/penpot/penpot-files/raw/main/welcome.penpot"}]

View File

@@ -20,12 +20,19 @@
<span>WEBHOOK</span>
</span>
{% endif %}
{% if item.params-schema-js %}
<span class="tag">
<span>SCHEMA</span>
</span>
{% endif %}
{% if item.spec %}
<span class="tag">
<span>SPEC</span>
</span>
{% endif %}
{% if item.sse %}
<span class="tag">
<span>SSE</span>

View File

@@ -7,7 +7,7 @@ Debug Main Page
{% block content %}
<nav>
<div class="title">
<h1>ADMIN DEBUG INTERFACE</h1>
<h1>ADMIN DEBUG INTERFACE (VERSION: {{version}})</h1>
</div>
</nav>
<main class="dashboard">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="30">
<Configuration status="fatal" monitorInterval="30">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] %level{length=1} %logger{36} - %msg%n"

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="30">
<Configuration status="fatal" monitorInterval="30">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] %level{length=1} %logger{36} - %msg%n"

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="30">
<Configuration status="fatal" monitorInterval="30">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] %level{length=1} %logger{36} - %msg%n"

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="60">
<Configuration status="fatal" monitorInterval="60">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] %level{length=1} %logger{36} - %msg%n"

View File

@@ -7,6 +7,8 @@ set -ex
rm -rf target;
mkdir -p target/classes;
mkdir -p target/dist;
mkdir -p target/dist/scripts;
echo "$CURRENT_VERSION" > target/classes/version.txt;
cp ../CHANGES.md target/classes/changelog.md;
@@ -15,6 +17,7 @@ mv target/penpot.jar target/dist/penpot.jar
cp resources/log4j2.xml target/dist/log4j2.xml
cp scripts/run.template.sh target/dist/run.sh;
cp scripts/manage.py target/dist/manage.py
cp scripts/svgo-cli.js target/dist/scripts/;
chmod +x target/dist/run.sh;
chmod +x target/dist/manage.py

View File

@@ -1,7 +1,6 @@
#!/usr/bin/env bash
export PENPOT_HOST=devenv
export PENPOT_TENANT=dev
export PENPOT_FLAGS="\
$PENPOT_FLAGS \
enable-login-with-ldap \
@@ -23,9 +22,12 @@ export PENPOT_FLAGS="\
enable-urepl-server \
enable-rpc-climit \
enable-rpc-rlimit \
enable-quotes \
enable-soft-rpc-rlimit \
enable-auto-file-snapshot \
enable-webhooks \
enable-access-tokens \
enable-tiered-file-data-storage \
enable-file-validation \
enable-file-schema-validation";
@@ -61,9 +63,11 @@ mc mb penpot-s3/penpot -p -q
export AWS_ACCESS_KEY_ID=penpot-devenv
export AWS_SECRET_ACCESS_KEY=penpot-devenv
export PENPOT_ASSETS_STORAGE_BACKEND=assets-s3
export PENPOT_STORAGE_ASSETS_S3_ENDPOINT=http://minio:9000
export PENPOT_STORAGE_ASSETS_S3_BUCKET=penpot
export PENPOT_OBJECTS_STORAGE_BACKEND=s3
export PENPOT_OBJECTS_STORAGE_S3_ENDPOINT=http://minio:9000
export PENPOT_OBJECTS_STORAGE_S3_BUCKET=penpot
export PENPOT_OBJECTS_STORAGE_FS_DIRECTORY="assets"
export OPTIONS="
-A:jmx-remote -A:dev \

View File

@@ -1,7 +1,6 @@
#!/usr/bin/env bash
export PENPOT_HOST=devenv
export PENPOT_TENANT=dev
export PENPOT_FLAGS="\
$PENPOT_FLAGS \
enable-prepl-server \
@@ -10,6 +9,7 @@ export PENPOT_FLAGS="\
enable-webhooks \
enable-backend-asserts \
enable-audit-log \
enable-login-with-ldap \
enable-transit-readable-response \
enable-demo-users \
enable-feature-fdata-pointer-map \
@@ -17,7 +17,10 @@ export PENPOT_FLAGS="\
disable-secure-session-cookies \
enable-rpc-climit \
enable-smtp \
enable-quotes \
enable-file-snapshot \
enable-access-tokens \
enable-tiered-file-data-storage \
enable-file-validation \
enable-file-schema-validation";
@@ -55,9 +58,9 @@ mc mb penpot-s3/penpot -p -q
export AWS_ACCESS_KEY_ID=penpot-devenv
export AWS_SECRET_ACCESS_KEY=penpot-devenv
export PENPOT_ASSETS_STORAGE_BACKEND=assets-s3
export PENPOT_STORAGE_ASSETS_S3_ENDPOINT=http://minio:9000
export PENPOT_STORAGE_ASSETS_S3_BUCKET=penpot
export PENPOT_OBJECTS_STORAGE_BACKEND=s3
export PENPOT_OBJECTS_STORAGE_S3_ENDPOINT=http://minio:9000
export PENPOT_OBJECTS_STORAGE_S3_BUCKET=penpot
entrypoint=${1:-app.main};

214
backend/scripts/svgo-cli.js Normal file
View File

File diff suppressed because one or more lines are too long

View File

@@ -8,10 +8,8 @@
(:require
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.spec :as us]
[app.config :as cf]
[app.common.schema :as sm]
[clj-ldap.client :as ldap]
[clojure.spec.alpha :as s]
[clojure.string]
[integrant.core :as ig]))
@@ -59,21 +57,26 @@
:email email
:backend "ldap"})))
(s/def ::fullname ::us/not-empty-string)
(s/def ::email ::us/email)
(s/def ::backend ::us/not-empty-string)
(def ^:private schema:info-data
[:map
[:fullname ::sm/text]
[:email ::sm/email]
[:backend ::sm/text]])
(s/def ::info-data
(s/keys :req-un [::fullname ::email ::backend]))
(def ^:private valid-info-data?
(sm/lazy-validator schema:info-data))
(def ^:private explain-info-data
(sm/lazy-explainer schema:info-data))
(defn authenticate
[cfg params]
(with-open [conn (connect cfg)]
(when-let [user (-> (assoc cfg ::conn conn)
(retrieve-user params))]
(when-not (s/valid? ::info-data user)
(let [explain (s/explain-str ::info-data user)]
(l/warn ::l/raw (str "invalid response from ldap, looks like ldap is not configured correctly\n" explain))
(when-not (valid-info-data? user)
(let [explain (explain-info-data user)]
(l/warn :hint "invalid response from ldap, looks like ldap is not configured correctly" :data user)
(ex/raise :type :restriction
:code :wrong-ldap-response
:explain explain)))
@@ -103,37 +106,31 @@
:host (:host cfg) :port (:port cfg) :cause cause)
nil))))
(s/def ::enabled? ::us/boolean)
(s/def ::host ::cf/ldap-host)
(s/def ::port ::cf/ldap-port)
(s/def ::ssl ::cf/ldap-ssl)
(s/def ::tls ::cf/ldap-starttls)
(s/def ::query ::cf/ldap-user-query)
(s/def ::base-dn ::cf/ldap-base-dn)
(s/def ::bind-dn ::cf/ldap-bind-dn)
(s/def ::bind-password ::cf/ldap-bind-password)
(s/def ::attrs-email ::cf/ldap-attrs-email)
(s/def ::attrs-fullname ::cf/ldap-attrs-fullname)
(s/def ::attrs-username ::cf/ldap-attrs-username)
(def ^:private schema:params
[:map
[:host {:optional true} :string]
[:port {:optional true} ::sm/int]
[:bind-dn {:optional true} :string]
[:bind-passwor {:optional true} :string]
[:query {:optional true} :string]
[:base-dn {:optional true} :string]
[:attrs-email {:optional true} :string]
[:attrs-username {:optional true} :string]
[:attrs-fullname {:optional true} :string]
[:ssl {:optional true} ::sm/boolean]
[:tls {:optional true} ::sm/boolean]])
(s/def ::provider-params
(s/keys :opt-un [::host ::port
::ssl ::tls
::enabled?
::bind-dn
::bind-password
::query
::attrs-email
::attrs-username
::attrs-fullname]))
(s/def ::provider
(s/nilable ::provider-params))
(def ^:private check-params
(sm/check-fn schema:params :hint "Invalid LDAP provider parameters"))
(defmethod ig/pre-init-spec ::provider
[_]
(s/spec ::provider))
(defmethod ig/assert-key ::provider
[_ params]
(when (:enabled params)
(some->> params check-params)))
(defmethod ig/init-key ::provider
[_ cfg]
(when (:enabled? cfg)
(when (:enabled cfg)
(try-connectivity cfg)))
(sm/register! ::provider schema:params)

View File

@@ -12,7 +12,7 @@
[app.common.data.macros :as dm]
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.common.uri :as u]
[app.config :as cf]
[app.db :as db]
@@ -32,11 +32,10 @@
[buddy.sign.jwk :as jwk]
[buddy.sign.jwt :as jwt]
[clojure.set :as set]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig]
[ring.request :as rreq]
[ring.response :as-alias rres]))
[yetti.request :as yreq]
[yetti.response :as-alias yres]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; HELPERS
@@ -140,8 +139,9 @@
(l/warn :hint "unable to retrieve JWKs (unexpected exception)"
:cause cause)))))
(defmethod ig/pre-init-spec ::providers/generic [_]
(s/keys :req [::http/client]))
(defmethod ig/assert-key ::providers/generic
[_ params]
(assert (http/client? (::http/client params)) "expected a valid http client"))
(defmethod ig/init-key ::providers/generic
[_ cfg]
@@ -197,6 +197,10 @@
;; GITHUB AUTH PROVIDER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- int-in-range?
[val start end]
(and (<= start val) (< val end)))
(defn- retrieve-github-email
[cfg tdata props]
(or (some-> props :github/email)
@@ -207,7 +211,7 @@
{:keys [status body]} (http/req! cfg params {:sync? true})]
(when-not (s/int-in-range? 200 300 status)
(when-not (int-in-range? status 200 300)
(ex/raise :type :internal
:code :unable-to-retrieve-github-emails
:hint "unable to retrieve github emails"
@@ -217,8 +221,9 @@
(->> body json/decode (filter :primary) first :email))))
(defmethod ig/pre-init-spec ::providers/github [_]
(s/keys :req [::http/client]))
(defmethod ig/assert-key ::providers/github
[_ params]
(assert (http/client? (::http/client params)) "expected a valid http client"))
(defmethod ig/init-key ::providers/github
[_ cfg]
@@ -394,7 +399,7 @@
:status (:status response)
:body (:body response))
(when-not (s/int-in-range? 200 300 (:status response))
(when-not (int-in-range? (:status response) 200 300)
(ex/raise :type :internal
:code :unable-to-retrieve-user-info
:hint "unable to retrieve user info"
@@ -418,15 +423,15 @@
(l/warn :hint "unable to get user info from JWT token (unexpected exception)"
:cause cause))))
(s/def ::backend ::us/not-empty-string)
(s/def ::email ::us/not-empty-string)
(s/def ::fullname ::us/not-empty-string)
(s/def ::props (s/map-of ::us/keyword any?))
(s/def ::info
(s/keys :req-un [::backend
::email
::fullname
::props]))
(def ^:private schema:info
[:map
[:backend ::sm/text]
[:email ::sm/email]
[:fullname ::sm/text]
[:props [:map-of :keyword :any]]])
(def ^:private valid-info?
(sm/validator schema:info))
(defn- get-info
[{:keys [::provider ::setup/props] :as cfg} {:keys [params] :as request}]
@@ -444,7 +449,7 @@
(l/trc :hint "user info" :info info)
(when-not (s/valid? ::info info)
(when-not (valid-info? info)
(l/warn :hint "received incomplete profile info object (please set correct scopes)" :info info)
(ex/raise :type :internal
:code :incomplete-user-info
@@ -492,8 +497,8 @@
(defn- redirect-response
[uri]
{::rres/status 302
::rres/headers {"location" (str uri)}})
{::yres/status 302
::yres/headers {"location" (str uri)}})
(defn- redirect-with-error
([error] (redirect-with-error error nil))
@@ -567,7 +572,6 @@
(tokens/generate (::setup/props cfg)
{:iss :auth
:exp (dt/in-future "15m")
:props (:props info)
:profile-id (:id profile)}))
props (audit/profile->props profile)
context (d/without-nils {:external-session-id (:external-session-id info)})]
@@ -599,7 +603,7 @@
(defn- get-external-session-id
[request]
(let [session-id (rreq/get-header request "x-external-session-id")]
(let [session-id (yreq/get-header request "x-external-session-id")]
(when (string? session-id)
(if (or (> (count session-id) 256)
(= session-id "null")
@@ -619,8 +623,8 @@
state (tokens/generate (::setup/props cfg)
(d/without-nils params))
uri (build-auth-uri cfg state)]
{::rres/status 200
::rres/body {:redirect-uri uri}}))
{::yres/status 200
::yres/body {:redirect-uri uri}}))
(defn- callback-handler
[{:keys [::provider] :as cfg} request]
@@ -656,46 +660,37 @@
:provider provider
:hint "provider not configured"))))))})
(s/def ::client-id ::cf/oidc-client-id)
(s/def ::client-secret ::cf/oidc-client-secret)
(s/def ::base-uri ::cf/oidc-base-uri)
(s/def ::token-uri ::cf/oidc-token-uri)
(s/def ::auth-uri ::cf/oidc-auth-uri)
(s/def ::user-uri ::cf/oidc-user-uri)
(s/def ::scopes ::cf/oidc-scopes)
(s/def ::roles ::cf/oidc-roles)
(s/def ::roles-attr ::cf/oidc-roles-attr)
(s/def ::email-attr ::cf/oidc-email-attr)
(s/def ::name-attr ::cf/oidc-name-attr)
(def ^:private schema:provider
[:map {:title "provider"}
[:client-id ::sm/text]
[:client-secret ::sm/text]
[:base-uri {:optional true} ::sm/text]
[:token-uri {:optional true} ::sm/text]
[:auth-uri {:optional true} ::sm/text]
[:user-uri {:optional true} ::sm/text]
[:scopes {:optional true}
[::sm/set ::sm/text]]
[:roles {:optional true}
[::sm/set ::sm/text]]
[:roles-attr {:optional true} ::sm/text]
[:email-attr {:optional true} ::sm/text]
[:name-attr {:optional true} ::sm/text]])
(s/def ::provider
(s/keys :req-un [::client-id
::client-secret]
:opt-un [::base-uri
::token-uri
::auth-uri
::user-uri
::scopes
::roles
::roles-attr
::email-attr
::name-attr]))
(def ^:private schema:routes-params
[:map
::session/manager
::http/client
::setup/props
::db/pool
[::providers [:map-of :keyword [:maybe schema:provider]]]])
(s/def ::providers (s/map-of ::us/keyword (s/nilable ::provider)))
(s/def ::routes vector?)
(defmethod ig/pre-init-spec ::routes
[_]
(s/keys :req [::session/manager
::http/client
::setup/props
::db/pool
::providers]))
(defmethod ig/assert-key ::routes
[_ params]
(assert (sm/check schema:routes-params params)))
(defmethod ig/init-key ::routes
[_ cfg]
(let [cfg (update cfg :provider d/without-nils)]
(let [cfg (update cfg :providers d/without-nils)]
["" {:middleware [[session/authz cfg]
[provider-lookup cfg]]}
["/auth/oauth"

View File

@@ -37,6 +37,21 @@
(def ^:dynamic *state* nil)
(def ^:dynamic *options* nil)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DEFAULTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Threshold in MiB when we pass from using
;; in-memory byte-array's to use temporal files.
(def temp-file-threshold
(* 1024 1024 2))
;; A maximum (storage) object size allowed: 100MiB
(def ^:const max-object-size
(* 1024 1024 100))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def xf-map-id
(map :id))
@@ -56,6 +71,13 @@
(def conj-vec
(fnil conj []))
(defn initial-state
[]
{:storage-objects #{}
:files #{}
:teams #{}
:projects #{}})
(defn collect-storage-objects
[state items]
(update state :storage-objects into xf-map-media-id items))
@@ -87,6 +109,8 @@
attrs))
(defn update-index
([coll]
(update-index {} coll identity))
([index coll]
(update-index index coll identity))
([index coll attr]
@@ -114,6 +138,16 @@
[cfg project-id]
(db/get cfg :project {:id project-id}))
(def ^:private sql:get-teams
"SELECT t.* FROM team WHERE id = ANY(?)")
(defn get-teams
[cfg ids]
(let [conn (db/get-connection cfg)
ids (db/create-array conn "uuid" ids)]
(->> (db/exec! conn [sql:get-teams ids])
(map decode-row))))
(defn get-team
[cfg team-id]
(-> (db/get cfg :team {:id team-id})
@@ -167,9 +201,10 @@
(defn get-file-object-thumbnails
"Return all file object thumbnails for a given file."
[cfg file-id]
(db/query cfg :file-tagged-object-thumbnail
{:file-id file-id
:deleted-at nil}))
(->> (db/query cfg :file-tagged-object-thumbnail
{:file-id file-id
:deleted-at nil})
(not-empty)))
(defn get-file-thumbnail
"Return the thumbnail for the specified file-id"
@@ -224,26 +259,26 @@
(->> (db/exec! conn [sql ids])
(mapv #(assoc % :file-id id)))))))
(def ^:private sql:get-team-files
(def ^:private sql:get-team-files-ids
"SELECT f.id FROM file AS f
JOIN project AS p ON (p.id = f.project_id)
WHERE p.team_id = ?")
(defn get-team-files
(defn get-team-files-ids
"Get a set of file ids for the specified team-id"
[{:keys [::db/conn]} team-id]
(->> (db/exec! conn [sql:get-team-files team-id])
(->> (db/exec! conn [sql:get-team-files-ids team-id])
(into #{} xf-map-id)))
(def ^:private sql:get-team-projects
"SELECT p.id FROM project AS p
"SELECT p.* FROM project AS p
WHERE p.team_id = ?
AND p.deleted_at IS NULL")
(defn get-team-projects
"Get a set of project ids for the team"
[{:keys [::db/conn]} team-id]
(->> (db/exec! conn [sql:get-team-projects team-id])
[cfg team-id]
(->> (db/exec! cfg [sql:get-team-projects team-id])
(into #{} xf-map-id)))
(def ^:private sql:get-project-files
@@ -257,6 +292,10 @@
(->> (db/exec! conn [sql:get-project-files project-id])
(into #{} xf-map-id)))
(defn remap-thumbnail-object-id
[object-id file-id]
(str/replace-first object-id #"^(.*?)/" (str file-id "/")))
(defn- relink-shapes
"A function responsible to analyze all file data and
replace the old :component-file reference with the new
@@ -339,6 +378,12 @@
data
library-ids)))
(defn disable-database-timeouts!
[cfg]
(let [conn (db/get-connection cfg)]
(db/exec-one! conn ["SET LOCAL idle_in_transaction_session_timeout = 0"])
(db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"])))
(defn- fix-version
[file]
(let [file (fmg/fix-version file)]
@@ -432,6 +477,20 @@
file))
(defn register-pending-migrations
"All features that are enabled and requires explicit migration are
added to the state for a posterior migration step."
[cfg {:keys [id features] :as file}]
(doseq [feature (-> (::features cfg)
(set/difference cfeat/no-migration-features)
(set/difference cfeat/backend-only-features)
(set/difference features))]
(vswap! *state* update :pending-to-migrate (fnil conj []) [feature id]))
file)
(defn apply-pending-migrations!
"Apply alredy registered pending migrations to files"
[cfg]

View File

@@ -22,7 +22,6 @@
[app.db :as db]
[app.loggers.audit :as-alias audit]
[app.loggers.webhooks :as-alias webhooks]
[app.media :as media]
[app.rpc :as-alias rpc]
[app.rpc.commands.teams :as teams]
[app.rpc.doc :as-alias doc]
@@ -50,15 +49,6 @@
(set! *warn-on-reflection* true)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DEFAULTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Threshold in MiB when we pass from using
;; in-memory byte-array's to use temporal files.
(def temp-file-threshold
(* 1024 1024 2))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; LOW LEVEL STREAM IO API
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -66,11 +56,6 @@
(def ^:const buffer-size (:xnio/buffer-size yt/defaults))
(def ^:const penpot-magic-number 800099563638710213)
;; A maximum (storage) object size allowed: 100MiB
(def ^:const max-object-size
(* 1024 1024 100))
(def ^:dynamic *position* nil)
(defn get-mark
@@ -237,7 +222,7 @@
(defn copy-stream!
[^OutputStream output ^InputStream input ^long size]
(let [written (io/copy! input output :size size)]
(let [written (io/copy input output :size size)]
(l/trace :fn "copy-stream!" :position @*position* :size size :written written ::l/sync? true)
(swap! *position* + written)
written))
@@ -259,18 +244,18 @@
p (tmp/tempfile :prefix "penpot.binfile.")]
(assert-mark m :stream)
(when (> s max-object-size)
(when (> s bfc/max-object-size)
(ex/raise :type :validation
:code :max-file-size-reached
:hint (str/ffmt "unable to import storage object with size % bytes" s)))
(if (> s temp-file-threshold)
(if (> s bfc/temp-file-threshold)
(with-open [^OutputStream output (io/output-stream p)]
(let [readed (io/copy! input output :offset 0 :size s)]
(let [readed (io/copy input output :offset 0 :size s)]
(l/trace :fn "read-stream*!" :expected s :readed readed :position @*position* ::l/sync? true)
(swap! *position* + readed)
[s p]))
[s (io/read-as-bytes input :size s)])))
[s (io/read input :size s)])))
(defmacro assert-read-label!
[input expected-label]
@@ -382,10 +367,12 @@
::l/sync? true)
(doseq [item media]
(l/dbg :hint "write penpot file media object" :id (:id item) ::l/sync? true))
(l/dbg :hint "write penpot file media object"
:id (:id item) ::l/sync? true))
(doseq [item thumbnails]
(l/dbg :hint "write penpot file object thumbnail" :media-id (str (:media-id item)) ::l/sync? true))
(l/dbg :hint "write penpot file object thumbnail"
:media-id (str (:media-id item)) ::l/sync? true))
(doto output
(write-obj! file)
@@ -403,9 +390,9 @@
(write-obj! output rels)))
(defmethod write-section :v1/sobjects
[{:keys [::sto/storage ::output]}]
[{:keys [::output] :as cfg}]
(let [sids (-> bfc/*state* deref :sids)
storage (media/configure-assets-storage storage)]
storage (sto/resolve cfg)]
(l/dbg :hint "found sobjects"
:items (count sids)
@@ -467,8 +454,8 @@
(defn- read-import-v1
[{:keys [::db/conn ::project-id ::profile-id ::input] :as cfg}]
(db/exec-one! conn ["SET LOCAL idle_in_transaction_session_timeout = 0"])
(db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"])
(bfc/disable-database-timeouts! cfg)
(pu/with-open [input (zstd-input-stream input)
input (io/data-input-stream input)]
@@ -560,7 +547,9 @@
(when (seq thumbnails)
(let [thumbnails (remap-thumbnails thumbnails file-id')]
(l/dbg :hint "updated index with thumbnails" :total (count thumbnails) ::l/sync? true)
(l/dbg :hint "updated index with thumbnails"
:total (count thumbnails)
::l/sync? true)
(vswap! bfc/*state* update :thumbnails bfc/into-vec thumbnails)))
(when (seq media)
@@ -620,8 +609,8 @@
::l/sync? true))))))
(defmethod read-section :v1/sobjects
[{:keys [::sto/storage ::db/conn ::input ::bfc/overwrite ::bfc/timestamp]}]
(let [storage (media/configure-assets-storage storage)
[{:keys [::db/conn ::input ::bfc/overwrite ::bfc/timestamp] :as cfg}]
(let [storage (sto/resolve cfg)
ids (read-obj! input)
thumb? (into #{} (map :media-id) (:thumbnails @bfc/*state*))]
@@ -710,7 +699,7 @@
(dm/assert!
"expected instance of jio/IOFactory for `input`"
(satisfies? jio/IOFactory output))
(io/coercible? output))
(let [id (uuid/next)
tp (dt/tpoint)
@@ -739,7 +728,7 @@
:cause @cs)))))
(defn import-files!
[cfg input]
[{:keys [::input] :as cfg}]
(dm/assert!
"expected valid profile-id and project-id on `cfg`"

View File

@@ -20,7 +20,6 @@
[app.db.sql :as sql]
[app.loggers.audit :as-alias audit]
[app.loggers.webhooks :as-alias webhooks]
[app.media :as media]
[app.storage :as sto]
[app.storage.tmp :as tmp]
[app.util.events :as events]
@@ -142,16 +141,15 @@
(write! cfg :team-font-variant id font))))
(defn- write-project!
[cfg project-id]
(let [project (bfc/get-project cfg project-id)]
(events/tap :progress
{:op :export
:section :write-project
:id project-id
:name (:name project)})
(l/trc :hint "write" :obj "project" :id (str project-id))
(write! cfg :project (str project-id) project)
(vswap! bfc/*state* update :projects conj project-id)))
[cfg project]
(events/tap :progress
{:op :export
:section :write-project
:id (:id project)
:name (:name project)})
(l/trc :hint "write" :obj "project" :id (str (:id project)))
(write! cfg :project (str (:id project)) project)
(vswap! bfc/*state* update :projects conj (:id project)))
(defn- write-file!
[cfg file-id]
@@ -192,7 +190,7 @@
[{:keys [::sto/storage] :as cfg} id]
(let [sobj (sto/get-object storage id)
data (with-open [input (sto/get-object-data storage sobj)]
(io/read-as-bytes input))]
(io/read input))]
(l/trc :hint "write" :obj "storage-object" :id (str id) :size (:size sobj))
(write! cfg :storage-object id (meta sobj) data)))
@@ -347,9 +345,7 @@
[cfg team-id]
(let [id (uuid/next)
tp (dt/tpoint)
cfg (-> (create-database cfg)
(update ::sto/storage media/configure-assets-storage))]
cfg (create-database cfg)]
(l/inf :hint "start"
:operation "export"
@@ -366,7 +362,7 @@
(bfc/get-team-projects cfg team-id))
(run! (partial write-file! cfg)
(bfc/get-team-files cfg team-id))
(bfc/get-team-files-ids cfg team-id))
(run! (partial write-storage-object! cfg)
(-> bfc/*state* deref :storage-objects))
@@ -390,7 +386,6 @@
tp (dt/tpoint)
cfg (-> (create-database cfg path)
(update ::sto/storage media/configure-assets-storage)
(assoc ::bfc/timestamp (dt/now)))]
(l/inf :hint "start"

View File

@@ -0,0 +1,957 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.binfile.v3
"A ZIP based binary file exportation"
(:refer-clojure :exclude [read])
(:require
[app.binfile.common :as bfc]
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.exceptions :as ex]
[app.common.json :as json]
[app.common.logging :as l]
[app.common.schema :as sm]
[app.common.thumbnails :as cth]
[app.common.types.color :as ctcl]
[app.common.types.component :as ctc]
[app.common.types.file :as ctf]
[app.common.types.page :as ctp]
[app.common.types.plugins :as ctpg]
[app.common.types.shape :as cts]
[app.common.types.typography :as cty]
[app.common.uuid :as uuid]
[app.config :as cf]
[app.db :as db]
[app.storage :as sto]
[app.storage.impl :as sto.impl]
[app.util.events :as events]
[app.util.time :as dt]
[clojure.java.io :as jio]
[cuerdas.core :as str]
[datoteka.fs :as fs]
[datoteka.io :as io])
(:import
java.io.InputStream
java.io.OutputStreamWriter
java.util.zip.ZipEntry
java.util.zip.ZipFile
java.util.zip.ZipOutputStream))
;; --- SCHEMA
(def ^:private schema:manifest
[:map {:title "Manifest"}
[:version ::sm/int]
[:type :string]
[:generated-by {:optional true} :string]
[:files
[:vector
[:map
[:id ::sm/uuid]
[:name :string]
[:project-id ::sm/uuid]]]]
[:relations {:optional true}
[:vector
[:tuple ::sm/uuid ::sm/uuid]]]])
(def ^:private schema:storage-object
[:map {:title "StorageObject"}
[:id ::sm/uuid]
[:size ::sm/int]
[:content-type :string]
[:bucket [::sm/one-of {:format :string} sto/valid-buckets]]
[:hash :string]])
(def ^:private schema:file-thumbnail
[:map {:title "FileThumbnail"}
[:file-id ::sm/uuid]
[:page-id ::sm/uuid]
[:frame-id ::sm/uuid]
[:tag :string]
[:media-id ::sm/uuid]])
;; --- ENCODERS
(def encode-file
(sm/encoder ::ctf/file sm/json-transformer))
(def encode-page
(sm/encoder ::ctp/page sm/json-transformer))
(def encode-shape
(sm/encoder ::cts/shape sm/json-transformer))
(def encode-media
(sm/encoder ::ctf/media sm/json-transformer))
(def encode-component
(sm/encoder ::ctc/component sm/json-transformer))
(def encode-color
(sm/encoder ::ctcl/color sm/json-transformer))
(def encode-typography
(sm/encoder ::cty/typography sm/json-transformer))
(def encode-plugin-data
(sm/encoder ::ctpg/plugin-data sm/json-transformer))
(def encode-storage-object
(sm/encoder schema:storage-object sm/json-transformer))
(def encode-file-thumbnail
(sm/encoder schema:file-thumbnail sm/json-transformer))
;; --- DECODERS
(def decode-manifest
(sm/decoder schema:manifest sm/json-transformer))
(def decode-media
(sm/decoder ::ctf/media sm/json-transformer))
(def decode-component
(sm/decoder ::ctc/component sm/json-transformer))
(def decode-color
(sm/decoder ::ctcl/color sm/json-transformer))
(def decode-file
(sm/decoder ::ctf/file sm/json-transformer))
(def decode-page
(sm/decoder ::ctp/page sm/json-transformer))
(def decode-shape
(sm/decoder ::cts/shape sm/json-transformer))
(def decode-typography
(sm/decoder ::cty/typography sm/json-transformer))
(def decode-plugin-data
(sm/decoder ::ctpg/plugin-data sm/json-transformer))
(def decode-storage-object
(sm/decoder schema:storage-object sm/json-transformer))
(def decode-file-thumbnail
(sm/decoder schema:file-thumbnail sm/json-transformer))
;; --- VALIDATORS
(def validate-manifest
(sm/check-fn schema:manifest))
(def validate-file
(sm/check-fn ::ctf/file))
(def validate-page
(sm/check-fn ::ctp/page))
(def validate-shape
(sm/check-fn ::cts/shape))
(def validate-media
(sm/check-fn ::ctf/media))
(def validate-color
(sm/check-fn ::ctcl/color))
(def validate-component
(sm/check-fn ::ctc/component))
(def validate-typography
(sm/check-fn ::cty/typography))
(def validate-plugin-data
(sm/check-fn ::ctpg/plugin-data))
(def validate-storage-object
(sm/check-fn schema:storage-object))
(def validate-file-thumbnail
(sm/check-fn schema:file-thumbnail))
;; --- EXPORT IMPL
(defn- write-entry!
[^ZipOutputStream output ^String path data]
(.putNextEntry output (ZipEntry. path))
(let [writer (OutputStreamWriter. output "UTF-8")]
(json/write writer data :indent true :key-fn json/write-camel-key)
(.flush writer))
(.closeEntry output))
(defn- get-file
[{:keys [::embed-assets ::include-libraries] :as cfg} file-id]
(when (and include-libraries embed-assets)
(throw (IllegalArgumentException.
"the `include-libraries` and `embed-assets` are mutally excluding options")))
(let [detach? (and (not embed-assets) (not include-libraries))]
(cond-> (bfc/get-file cfg file-id)
detach?
(-> (ctf/detach-external-references file-id)
(dissoc :libraries))
embed-assets
(update :data #(bfc/embed-assets cfg % file-id)))))
(defn- resolve-extension
[mtype]
(case mtype
"image/png" ".png"
"image/jpeg" ".jpg"
"image/gif" ".gif"
"image/svg+xml" ".svg"
"image/webp" ".webp"
"font/woff" ".woff"
"font/woff2" ".woff2"
"font/ttf" ".ttf"
"font/otf" ".otf"
"application/octet-stream" ".bin"))
(defn- export-storage-objects
[{:keys [::output] :as cfg}]
(let [storage (sto/resolve cfg)]
(doseq [id (-> bfc/*state* deref :storage-objects not-empty)]
(let [sobject (sto/get-object storage id)
smeta (meta sobject)
ext (resolve-extension (:content-type smeta))
path (str "objects/" id ".json")
params (-> (meta sobject)
(assoc :id (:id sobject))
(assoc :size (:size sobject))
(encode-storage-object))]
(write-entry! output path params)
(with-open [input (sto/get-object-data storage sobject)]
(.putNextEntry output (ZipEntry. (str "objects/" id ext)))
(io/copy input output :size (:size sobject))
(.closeEntry output))))))
(defn- export-file
[{:keys [::file-id ::output] :as cfg}]
(let [file (get-file cfg file-id)
media (->> (bfc/get-file-media cfg file)
(map (fn [media]
(dissoc media :file-id))))
data (:data file)
typographies (:typographies data)
components (:components data)
colors (:colors data)
pages (:pages data)
pages-index (:pages-index data)
thumbnails (bfc/get-file-object-thumbnails cfg file-id)]
(vswap! bfc/*state* update :files assoc file-id
{:id file-id
:project-id (:project-id file)
:name (:name file)})
(let [file (cond-> (dissoc file :data)
(:options data)
(assoc :options (:options data))
:always
(encode-file))
path (str "files/" file-id ".json")]
(write-entry! output path file))
(doseq [[index page-id] (d/enumerate pages)]
(let [path (str "files/" file-id "/pages/" page-id ".json")
page (get pages-index page-id)
objects (:objects page)
page (-> page
(dissoc :objects)
(assoc :index index))
page (encode-page page)]
(write-entry! output path page)
(doseq [[shape-id shape] objects]
(let [path (str "files/" file-id "/pages/" page-id "/" shape-id ".json")
shape (assoc shape :page-id page-id)
shape (encode-shape shape)]
(write-entry! output path shape)))))
(vswap! bfc/*state* bfc/collect-storage-objects media)
(vswap! bfc/*state* bfc/collect-storage-objects thumbnails)
(doseq [{:keys [id] :as media} media]
(let [path (str "files/" file-id "/media/" id ".json")
media (encode-media media)]
(write-entry! output path media)))
(doseq [thumbnail thumbnails]
(let [data (cth/parse-object-id (:object-id thumbnail))
path (str "files/" file-id "/thumbnails/" (:tag data) "/" (:page-id data)
"/" (:frame-id data) ".json")
data (-> data
(assoc :media-id (:media-id thumbnail))
(encode-file-thumbnail))]
(write-entry! output path data)))
(doseq [[id component] components]
(let [path (str "files/" file-id "/components/" id ".json")
component (encode-component component)]
(write-entry! output path component)))
(doseq [[id color] colors]
(let [path (str "files/" file-id "/colors/" id ".json")
color (-> (encode-color color)
(dissoc :file-id))
color (cond-> color
(and (contains? color :path)
(str/empty? (:path color)))
(dissoc :path))]
(write-entry! output path color)))
(doseq [[id object] typographies]
(let [path (str "files/" file-id "/typographies/" id ".json")
color (encode-typography object)]
(write-entry! output path color)))))
(defn- export-files
[{:keys [::ids ::include-libraries ::output] :as cfg}]
(let [ids (into ids (when include-libraries (bfc/get-libraries cfg ids)))
rels (if include-libraries
(->> (bfc/get-files-rels cfg ids)
(mapv (juxt :file-id :library-file-id)))
[])]
(vswap! bfc/*state* assoc :files (d/ordered-map))
;; Write all the exporting files
(doseq [[index file-id] (d/enumerate ids)]
(-> cfg
(assoc ::file-id file-id)
(assoc ::file-seqn index)
(export-file)))
;; Write manifest file
(let [files (:files @bfc/*state*)
params {:type "penpot/export-files"
:version 1
:generated-by (str "penpot/" (:full cf/version))
:files (vec (vals files))
:relations rels}]
(write-entry! output "manifest.json" params))))
;; --- IMPORT IMPL
(defn- read-zip-entries
[^ZipFile input]
(into #{} (iterator-seq (.entries input))))
(defn- get-zip-entry*
[^ZipFile input ^String path]
(.getEntry input path))
(defn- get-zip-entry
[input path]
(let [entry (get-zip-entry* input path)]
(when-not entry
(ex/raise :type :validation
:code :inconsistent-penpot-file
:hint "the penpot file seems corrupt, missing underlying zip entry"
:path path))
entry))
(defn- get-zip-entry-size
[^ZipEntry entry]
(.getSize entry))
(defn- zip-entry-name
[^ZipEntry entry]
(.getName entry))
(defn- zip-entry-stream
^InputStream
[^ZipFile input ^ZipEntry entry]
(.getInputStream input entry))
(defn- zip-entry-reader
[^ZipFile input ^ZipEntry entry]
(-> (zip-entry-stream input entry)
(io/reader :encoding "UTF-8")))
(defn- zip-entry-storage-content
"Wraps a ZipFile and ZipEntry into a penpot storage compatible
object and avoid creating temporal objects"
[input entry]
(let [hash (delay (->> entry
(zip-entry-stream input)
(sto.impl/calculate-hash)))]
(reify
sto.impl/IContentObject
(get-size [_]
(get-zip-entry-size entry))
sto.impl/IContentHash
(get-hash [_]
(deref hash))
jio/IOFactory
(make-reader [this opts]
(jio/make-reader this opts))
(make-writer [_ _]
(throw (UnsupportedOperationException. "not implemented")))
(make-input-stream [_ _]
(zip-entry-stream input entry))
(make-output-stream [_ _]
(throw (UnsupportedOperationException. "not implemented"))))))
(defn- read-manifest
[^ZipFile input]
(let [entry (get-zip-entry input "manifest.json")]
(with-open [reader (zip-entry-reader input entry)]
(let [manifest (json/read reader :key-fn json/read-kebab-key)]
(decode-manifest manifest)))))
(defn- match-media-entry-fn
[file-id]
(let [pattern (str "^files/" file-id "/media/([^/]+).json$")
pattern (re-pattern pattern)]
(fn [entry]
(when-let [[_ id] (re-matches pattern (zip-entry-name entry))]
{:entry entry
:id (parse-uuid id)}))))
(defn- match-color-entry-fn
[file-id]
(let [pattern (str "^files/" file-id "/colors/([^/]+).json$")
pattern (re-pattern pattern)]
(fn [entry]
(when-let [[_ id] (re-matches pattern (zip-entry-name entry))]
{:entry entry
:id (parse-uuid id)}))))
(defn- match-component-entry-fn
[file-id]
(let [pattern (str "^files/" file-id "/components/([^/]+).json$")
pattern (re-pattern pattern)]
(fn [entry]
(when-let [[_ id] (re-matches pattern (zip-entry-name entry))]
{:entry entry
:id (parse-uuid id)}))))
(defn- match-typography-entry-fn
[file-id]
(let [pattern (str "^files/" file-id "/typographies/([^/]+).json$")
pattern (re-pattern pattern)]
(fn [entry]
(when-let [[_ id] (re-matches pattern (zip-entry-name entry))]
{:entry entry
:id (parse-uuid id)}))))
(defn- match-thumbnail-entry-fn
[file-id]
(let [pattern (str "^files/" file-id "/thumbnails/([^/]+)/([^/]+)/([^/]+).json$")
pattern (re-pattern pattern)]
(fn [entry]
(when-let [[_ tag page-id frame-id] (re-matches pattern (zip-entry-name entry))]
{:entry entry
:tag tag
:page-id (parse-uuid page-id)
:frame-id (parse-uuid frame-id)
:file-id file-id}))))
(defn- match-page-entry-fn
[file-id]
(let [pattern (str "^files/" file-id "/pages/([^/]+).json$")
pattern (re-pattern pattern)]
(fn [entry]
(when-let [[_ id] (re-matches pattern (zip-entry-name entry))]
{:entry entry
:id (parse-uuid id)}))))
(defn- match-shape-entry-fn
[file-id page-id]
(let [pattern (str "^files/" file-id "/pages/" page-id "/([^/]+).json$")
pattern (re-pattern pattern)]
(fn [entry]
(when-let [[_ id] (re-matches pattern (zip-entry-name entry))]
{:entry entry
:page-id page-id
:id (parse-uuid id)}))))
(defn- match-storage-entry-fn
[]
(let [pattern (str "^objects/([^/]+).json$")
pattern (re-pattern pattern)]
(fn [entry]
(when-let [[_ id] (re-matches pattern (zip-entry-name entry))]
{:entry entry
:id (parse-uuid id)}))))
(defn- read-entry
[^ZipFile input entry]
(with-open [reader (zip-entry-reader input entry)]
(json/read reader :key-fn json/read-kebab-key)))
(defn- read-file
[{:keys [::input ::file-id]}]
(let [path (str "files/" file-id ".json")
entry (get-zip-entry input path)]
(-> (read-entry input entry)
(decode-file)
(validate-file))))
(defn- read-file-plugin-data
[{:keys [::input ::file-id]}]
(let [path (str "files/" file-id "/plugin-data.json")
entry (get-zip-entry* input path)]
(some->> entry
(read-entry input)
(decode-plugin-data)
(validate-plugin-data))))
(defn- read-file-media
[{:keys [::input ::file-id ::entries]}]
(->> (keep (match-media-entry-fn file-id) entries)
(reduce (fn [result {:keys [id entry]}]
(let [object (->> (read-entry input entry)
(decode-media)
(validate-media))
object (assoc object :file-id file-id)]
(if (= id (:id object))
(conj result object)
result)))
[])
(not-empty)))
(defn- read-file-colors
[{:keys [::input ::file-id ::entries]}]
(->> (keep (match-color-entry-fn file-id) entries)
(reduce (fn [result {:keys [id entry]}]
(let [object (->> (read-entry input entry)
(decode-color)
(validate-color))]
(if (= id (:id object))
(assoc result id object)
result)))
{})
(not-empty)))
(defn- read-file-components
[{:keys [::input ::file-id ::entries]}]
(->> (keep (match-component-entry-fn file-id) entries)
(reduce (fn [result {:keys [id entry]}]
(let [object (->> (read-entry input entry)
(decode-component)
(validate-component))]
(if (= id (:id object))
(assoc result id object)
result)))
{})
(not-empty)))
(defn- read-file-typographies
[{:keys [::input ::file-id ::entries]}]
(->> (keep (match-typography-entry-fn file-id) entries)
(reduce (fn [result {:keys [id entry]}]
(let [object (->> (read-entry input entry)
(decode-typography)
(validate-typography))]
(if (= id (:id object))
(assoc result id object)
result)))
{})
(not-empty)))
(defn- read-file-shapes
[{:keys [::input ::file-id ::page-id ::entries] :as cfg}]
(->> (keep (match-shape-entry-fn file-id page-id) entries)
(reduce (fn [result {:keys [id entry]}]
(let [object (->> (read-entry input entry)
(decode-shape)
(validate-shape))]
(if (= id (:id object))
(assoc result id object)
result)))
{})
(not-empty)))
(defn- read-file-pages
[{:keys [::input ::file-id ::entries] :as cfg}]
(->> (keep (match-page-entry-fn file-id) entries)
(keep (fn [{:keys [id entry]}]
(let [page (->> (read-entry input entry)
(decode-page))
page (dissoc page :options)]
(when (= id (:id page))
(let [objects (-> (assoc cfg ::page-id id)
(read-file-shapes))]
(assoc page :objects objects))))))
(sort-by :index)
(reduce (fn [result {:keys [id] :as page}]
(assoc result id (dissoc page :index)))
(d/ordered-map))))
(defn- read-file-thumbnails
[{:keys [::input ::file-id ::entries] :as cfg}]
(->> (keep (match-thumbnail-entry-fn file-id) entries)
(reduce (fn [result {:keys [page-id frame-id tag entry]}]
(let [object (->> (read-entry input entry)
(decode-file-thumbnail)
(validate-file-thumbnail))]
(if (and (= frame-id (:frame-id object))
(= page-id (:page-id object))
(= tag (:tag object)))
(conj result object)
result)))
[])
(not-empty)))
(defn- read-file-data
[{:keys [] :as cfg}]
(let [colors (read-file-colors cfg)
typographies (read-file-typographies cfg)
components (read-file-components cfg)
plugin-data (read-file-plugin-data cfg)
pages (read-file-pages cfg)]
{:pages (-> pages keys vec)
:pages-index (into {} pages)
:colors colors
:typographies typographies
:components components
:plugin-data plugin-data}))
(defn- import-file
[{:keys [::db/conn ::project-id ::file-id ::file-name] :as cfg}]
(let [file-id' (bfc/lookup-index file-id)
file (read-file cfg)
media (read-file-media cfg)
thumbnails (read-file-thumbnails cfg)]
(l/dbg :hint "processing file"
:id (str file-id')
:prev-id (str file-id)
:features (str/join "," (:features file))
:version (:version file)
::l/sync? true)
(events/tap :progress {:section :file :name file-name})
(when media
;; Update index with media
(l/dbg :hint "update media index"
:file-id (str file-id')
:total (count media)
::l/sync? true)
(vswap! bfc/*state* update :index bfc/update-index (map :id media))
(vswap! bfc/*state* update :media into media))
(when thumbnails
(l/dbg :hint "update thumbnails index"
:file-id (str file-id')
:total (count thumbnails)
::l/sync? true)
(vswap! bfc/*state* update :index bfc/update-index (map :media-id thumbnails))
(vswap! bfc/*state* update :thumbnails into thumbnails))
(let [data (-> (read-file-data cfg)
(d/without-nils)
(assoc :id file-id')
(cond-> (:options file)
(assoc :options (:options file))))
file (-> file
(assoc :id file-id')
(assoc :data data)
(assoc :name file-name)
(assoc :project-id project-id)
(dissoc :options)
(bfc/process-file))]
(->> file
(bfc/register-pending-migrations cfg)
(bfc/persist-file! cfg))
(when (::bfc/overwrite cfg)
(db/delete! conn :file-thumbnail {:file-id file-id'}))
file-id')))
(defn- import-file-relations
[{:keys [::db/conn ::manifest ::bfc/timestamp] :as cfg}]
(events/tap :progress {:section :relations})
(doseq [[file-id libr-id] (:relations manifest)]
(let [file-id (bfc/lookup-index file-id)
libr-id (bfc/lookup-index libr-id)]
(when (and file-id libr-id)
(l/dbg :hint "create file library link"
:file-id (str file-id)
:lib-id (str libr-id)
::l/sync? true)
(db/insert! conn :file-library-rel
{:synced-at timestamp
:file-id file-id
:library-file-id libr-id})))))
(defn- import-storage-objects
[{:keys [::input ::entries ::bfc/timestamp] :as cfg}]
(events/tap :progress {:section :storage-objects})
(let [storage (sto/resolve cfg)
entries (keep (match-storage-entry-fn) entries)]
(doseq [{:keys [id entry]} entries]
(let [object (->> (read-entry input entry)
(decode-storage-object)
(validate-storage-object))]
(when (not= id (:id object))
(ex/raise :type :validation
:code :inconsistent-penpot-file
:hint "the penpot file seems corrupt, found unexpected uuid (storage-object-id)"
:expected-id (str id)
:found-id (str (:id object))))
(let [ext (resolve-extension (:content-type object))
path (str "objects/" id ext)
content (->> path
(get-zip-entry input)
(zip-entry-storage-content input))]
(when (not= (:size object) (sto/get-size content))
(ex/raise :type :validation
:code :inconsistent-penpot-file
:hint "found corrupted storage object: size does not match"
:path path
:expected-size (:size object)
:found-size (sto/get-size content)))
(when (not= (:hash object) (sto/get-hash content))
(ex/raise :type :validation
:code :inconsistent-penpot-file
:hint "found corrupted storage object: hash does not match"
:path path
:expected-hash (:hash object)
:found-hash (sto/get-hash content)))
(let [params (-> object
(dissoc :id :size)
(assoc ::sto/content content)
(assoc ::sto/deduplicate? true)
(assoc ::sto/touched-at timestamp))
sobject (sto/put-object! storage params)]
(l/dbg :hint "persisted storage object"
:id (str (:id sobject))
:prev-id (str id)
:bucket (:bucket params)
::l/sync? true)
(vswap! bfc/*state* update :index assoc id (:id sobject))))))))
(defn- import-file-media
[{:keys [::db/conn] :as cfg}]
(events/tap :progress {:section :media})
(doseq [item (:media @bfc/*state*)]
(let [params (-> item
(update :id bfc/lookup-index)
(update :file-id bfc/lookup-index)
(d/update-when :media-id bfc/lookup-index)
(d/update-when :thumbnail-id bfc/lookup-index))]
(l/dbg :hint "inserting file media object"
:id (str (:id params))
:file-id (str (:file-id params))
::l/sync? true)
(db/insert! conn :file-media-object params
{::db/on-conflict-do-nothing? (::bfc/overwrite cfg)}))))
(defn- import-file-thumbnails
[{:keys [::db/conn] :as cfg}]
(events/tap :progress {:section :thumbnails})
(doseq [item (:thumbnails @bfc/*state*)]
(let [file-id (bfc/lookup-index (:file-id item))
media-id (bfc/lookup-index (:media-id item))
object-id (-> (assoc item :file-id file-id)
(cth/fmt-object-id))
params {:file-id file-id
:object-id object-id
:tag (:tag item)
:media-id media-id}]
(l/dbg :hint "inserting file object thumbnail"
:file-id (str file-id)
:media-id (str media-id)
::l/sync? true)
(db/insert! conn :file-tagged-object-thumbnail params
{::db/on-conflict-do-nothing? (::bfc/overwrite cfg)}))))
(defn- import-files
[{:keys [::bfc/timestamp ::input ::name] :or {timestamp (dt/now)} :as cfg}]
(dm/assert!
"expected zip file"
(instance? ZipFile input))
(dm/assert!
"expected valid instant"
(dt/instant? timestamp))
(let [manifest (-> (read-manifest input)
(validate-manifest))
entries (read-zip-entries input)]
(when-not (= "penpot/export-files" (:type manifest))
(ex/raise :type :validation
:code :invalid-binfile-v3-manifest
:hint "unexpected type on manifest"
:manifest manifest))
;; Check if all files referenced on manifest are present
(doseq [{file-id :id} (:files manifest)]
(let [path (str "files/" file-id ".json")]
(when-not (get-zip-entry input path)
(ex/raise :type :validation
:code :invalid-binfile-v3
:hint "some files referenced on manifest not found"
:path path
:file-id file-id))))
(events/tap :progress {:section :manifest})
(let [index (bfc/update-index (map :id (:files manifest)))
state {:media [] :index index}
cfg (-> cfg
(assoc ::entries entries)
(assoc ::manifest manifest)
(assoc ::bfc/timestamp timestamp))]
(binding [bfc/*state* (volatile! state)]
(db/tx-run! cfg (fn [cfg]
(bfc/disable-database-timeouts! cfg)
(let [ids (->> (:files manifest)
(reduce (fn [result {:keys [id] :as file}]
(let [name' (get file :name)
name' (if (map? name)
(get name id)
name')]
(conj result (-> cfg
(assoc ::file-id id)
(assoc ::file-name name')
(import-file)))))
[]))]
(import-file-relations cfg)
(import-storage-objects cfg)
(import-file-media cfg)
(import-file-thumbnails cfg)
(bfc/apply-pending-migrations! cfg)
ids)))))))
;; --- PUBLIC API
(defn export-files!
"Do the exportation of a specified file in custom penpot binary
format. There are some options available for customize the output:
`::include-libraries`: additionally to the specified file, all the
linked libraries also will be included (including transitive
dependencies).
`::embed-assets`: instead of including the libraries, embed in the
same file library all assets used from external libraries."
[{:keys [::ids] :as cfg} output]
(dm/assert!
"expected a set of uuid's for `::ids` parameter"
(and (set? ids)
(every? uuid? ids)))
(dm/assert!
"expected instance of jio/IOFactory for `input`"
(satisfies? jio/IOFactory output))
(let [id (uuid/next)
tp (dt/tpoint)
ab (volatile! false)
cs (volatile! nil)]
(try
(l/info :hint "start exportation" :export-id (str id))
(binding [bfc/*state* (volatile! (bfc/initial-state))]
(with-open [output (io/output-stream output)]
(with-open [output (ZipOutputStream. output)]
(let [cfg (assoc cfg ::output output)]
(export-files cfg)
(export-storage-objects cfg)))))
(catch java.util.zip.ZipException cause
(vreset! cs cause)
(vreset! ab true)
(throw cause))
(catch java.io.IOException _cause
;; Do nothing, EOF means client closes connection abruptly
(vreset! ab true)
nil)
(catch Throwable cause
(vreset! cs cause)
(vreset! ab true)
(throw cause))
(finally
(l/info :hint "exportation finished" :export-id (str id)
:elapsed (str (inst-ms (tp)) "ms")
:aborted @ab
:cause @cs)))))
(defn import-files!
[{:keys [::input] :as cfg}]
(dm/assert!
"expected valid profile-id and project-id on `cfg`"
(and (uuid? (::profile-id cfg))
(uuid? (::project-id cfg))))
(dm/assert!
"expected instance of jio/IOFactory for `input`"
(io/coercible? input))
(let [id (uuid/next)
tp (dt/tpoint)
cs (volatile! nil)]
(l/info :hint "import: started" :id (str id))
(try
(with-open [input (ZipFile. (fs/file input))]
(import-files (assoc cfg ::input input)))
(catch Throwable cause
(vreset! cs cause)
(throw cause))
(finally
(l/info :hint "import: terminated"
:id (str id)
:elapsed (dt/format-duration (tp))
:error? (some? @cs))))))

View File

@@ -11,52 +11,40 @@
[app.common.data :as d]
[app.common.exceptions :as ex]
[app.common.flags :as flags]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.common.version :as v]
[app.util.overrides]
[app.util.time :as dt]
[clojure.core :as c]
[clojure.java.io :as io]
[clojure.pprint :as pprint]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[datoteka.fs :as fs]
[environ.core :refer [env]]
[integrant.core :as ig]))
(prefer-method print-method
clojure.lang.IRecord
clojure.lang.IDeref)
(prefer-method print-method
clojure.lang.IPersistentMap
clojure.lang.IDeref)
(prefer-method pprint/simple-dispatch
clojure.lang.IPersistentMap
clojure.lang.IDeref)
(defmethod ig/init-key :default
[_ data]
(d/without-nils data))
(defmethod ig/prep-key :default
[_ data]
(if (map? data)
(d/without-nils data)
data))
(defmethod ig/expand-key :default
[k v]
{k (if (map? v)
(d/without-nils v)
v)})
(def defaults
(def default
{:database-uri "postgresql://postgres/penpot"
:database-username "penpot"
:database-password "penpot"
:default-blob-version 5
:default-blob-version 4
:rpc-rlimit-config (fs/path "resources/rlimit.edn")
:rpc-climit-config (fs/path "resources/climit.edn")
:rpc-rlimit-config "resources/rlimit.edn"
:rpc-climit-config "resources/climit.edn"
:file-change-snapshot-every 5
:file-change-snapshot-timeout "3h"
:auto-file-snapshot-total 10
:auto-file-snapshot-every 5
:auto-file-snapshot-timeout "3h"
:public-uri "http://localhost:3449"
:host "localhost"
@@ -64,8 +52,8 @@
:redis-uri "redis://redis/0"
:assets-storage-backend :assets-fs
:storage-assets-fs-directory "assets"
:objects-storage-backend "fs"
:objects-storage-fs-directory "assets"
:assets-path "/internal/assets/"
:smtp-default-reply-to "Penpot <no-reply@example.com>"
@@ -92,254 +80,153 @@
;; time to avoid email sending after profile modification
:email-verify-threshold "15m"})
(s/def ::default-rpc-rlimit ::us/vector-of-strings)
(s/def ::rpc-rlimit-config ::fs/path)
(s/def ::rpc-climit-config ::fs/path)
(def schema:config
(do #_sm/optional-keys
[:map {:title "config"}
[:flags {:optional true} [::sm/set :string]]
[:admins {:optional true} [::sm/set ::sm/email]]
[:secret-key {:optional true} :string]
(s/def ::media-max-file-size ::us/integer)
[:tenant {:optional false} :string]
[:public-uri {:optional false} :string]
[:host {:optional false} :string]
(s/def ::flags ::us/vector-of-keywords)
(s/def ::telemetry-enabled ::us/boolean)
[:http-server-port {:optional true} ::sm/int]
[:http-server-host {:optional true} :string]
[:http-server-max-body-size {:optional true} ::sm/int]
[:http-server-max-multipart-body-size {:optional true} ::sm/int]
[:http-server-io-threads {:optional true} ::sm/int]
[:http-server-worker-threads {:optional true} ::sm/int]
(s/def ::audit-log-archive-uri ::us/string)
(s/def ::audit-log-http-handler-concurrency ::us/integer)
[:telemetry-uri {:optional true} :string]
[:telemetry-with-taiga {:optional true} ::sm/boolean] ;; DELETE
(s/def ::email-domain-blacklist ::fs/path)
(s/def ::email-domain-whitelist ::fs/path)
[:auto-file-snapshot-total {:optional true} ::sm/int]
[:auto-file-snapshot-every {:optional true} ::sm/int]
[:auto-file-snapshot-timeout {:optional true} ::dt/duration]
(s/def ::deletion-delay ::dt/duration)
[:media-max-file-size {:optional true} ::sm/int]
[:deletion-delay {:optional true} ::dt/duration] ;; REVIEW
[:telemetry-enabled {:optional true} ::sm/boolean]
[:default-blob-version {:optional true} ::sm/int]
[:allow-demo-users {:optional true} ::sm/boolean]
[:error-report-webhook {:optional true} :string]
[:user-feedback-destination {:optional true} :string]
(s/def ::admins ::us/set-of-valid-emails)
(s/def ::file-change-snapshot-every ::us/integer)
(s/def ::file-change-snapshot-timeout ::dt/duration)
[:default-rpc-rlimit {:optional true} [::sm/vec :string]]
[:rpc-rlimit-config {:optional true} ::fs/path]
[:rpc-climit-config {:optional true} ::fs/path]
(s/def ::default-executor-parallelism ::us/integer)
(s/def ::scheduled-executor-parallelism ::us/integer)
[:audit-log-archive-uri {:optional true} :string]
[:audit-log-http-handler-concurrency {:optional true} ::sm/int]
(s/def ::worker-default-parallelism ::us/integer)
(s/def ::worker-webhook-parallelism ::us/integer)
[:default-executor-parallelism {:optional true} ::sm/int] ;; REVIEW
[:scheduled-executor-parallelism {:optional true} ::sm/int] ;; REVIEW
[:worker-default-parallelism {:optional true} ::sm/int]
[:worker-webhook-parallelism {:optional true} ::sm/int]
(s/def ::auth-data-cookie-domain ::us/string)
(s/def ::auth-token-cookie-name ::us/string)
(s/def ::auth-token-cookie-max-age ::dt/duration)
[:database-password {:optional true} [:maybe :string]]
[:database-uri {:optional true} ::sm/uri]
[:database-username {:optional true} [:maybe :string]]
[:database-readonly {:optional true} ::sm/boolean]
[:database-min-pool-size {:optional true} ::sm/int]
[:database-max-pool-size {:optional true} ::sm/int]
(s/def ::secret-key ::us/string)
(s/def ::allow-demo-users ::us/boolean)
(s/def ::assets-path ::us/string)
(s/def ::database-password (s/nilable ::us/string))
(s/def ::database-uri ::us/string)
(s/def ::database-username (s/nilable ::us/string))
(s/def ::database-readonly ::us/boolean)
(s/def ::database-min-pool-size ::us/integer)
(s/def ::database-max-pool-size ::us/integer)
[:quotes-teams-per-profile {:optional true} ::sm/int]
[:quotes-access-tokens-per-profile {:optional true} ::sm/int]
[:quotes-projects-per-team {:optional true} ::sm/int]
[:quotes-invitations-per-team {:optional true} ::sm/int]
[:quotes-profiles-per-team {:optional true} ::sm/int]
[:quotes-files-per-project {:optional true} ::sm/int]
[:quotes-files-per-team {:optional true} ::sm/int]
[:quotes-font-variants-per-team {:optional true} ::sm/int]
[:quotes-comment-threads-per-file {:optional true} ::sm/int]
[:quotes-comments-per-file {:optional true} ::sm/int]
[:quotes-snapshots-per-file {:optional true} ::sm/int]
[:quotes-snapshots-per-team {:optional true} ::sm/int]
(s/def ::quotes-teams-per-profile ::us/integer)
(s/def ::quotes-access-tokens-per-profile ::us/integer)
(s/def ::quotes-projects-per-team ::us/integer)
(s/def ::quotes-invitations-per-team ::us/integer)
(s/def ::quotes-profiles-per-team ::us/integer)
(s/def ::quotes-files-per-project ::us/integer)
(s/def ::quotes-files-per-team ::us/integer)
(s/def ::quotes-font-variants-per-team ::us/integer)
(s/def ::quotes-comment-threads-per-file ::us/integer)
(s/def ::quotes-comments-per-file ::us/integer)
[:auth-data-cookie-domain {:optional true} :string]
[:auth-token-cookie-name {:optional true} :string]
[:auth-token-cookie-max-age {:optional true} ::dt/duration]
(s/def ::default-blob-version ::us/integer)
(s/def ::error-report-webhook ::us/string)
(s/def ::user-feedback-destination ::us/string)
(s/def ::github-client-id ::us/string)
(s/def ::github-client-secret ::us/string)
(s/def ::gitlab-base-uri ::us/string)
(s/def ::gitlab-client-id ::us/string)
(s/def ::gitlab-client-secret ::us/string)
(s/def ::google-client-id ::us/string)
(s/def ::google-client-secret ::us/string)
(s/def ::oidc-client-id ::us/string)
(s/def ::oidc-user-info-source ::us/keyword)
(s/def ::oidc-client-secret ::us/string)
(s/def ::oidc-base-uri ::us/string)
(s/def ::oidc-token-uri ::us/string)
(s/def ::oidc-auth-uri ::us/string)
(s/def ::oidc-user-uri ::us/string)
(s/def ::oidc-jwks-uri ::us/string)
(s/def ::oidc-scopes ::us/set-of-strings)
(s/def ::oidc-roles ::us/set-of-strings)
(s/def ::oidc-roles-attr ::us/string)
(s/def ::oidc-email-attr ::us/string)
(s/def ::oidc-name-attr ::us/string)
(s/def ::host ::us/string)
(s/def ::http-server-port ::us/integer)
(s/def ::http-server-host ::us/string)
(s/def ::http-server-max-body-size ::us/integer)
(s/def ::http-server-max-multipart-body-size ::us/integer)
(s/def ::http-server-io-threads ::us/integer)
(s/def ::http-server-worker-threads ::us/integer)
(s/def ::ldap-attrs-email ::us/string)
(s/def ::ldap-attrs-fullname ::us/string)
(s/def ::ldap-attrs-username ::us/string)
(s/def ::ldap-base-dn ::us/string)
(s/def ::ldap-bind-dn ::us/string)
(s/def ::ldap-bind-password ::us/string)
(s/def ::ldap-host ::us/string)
(s/def ::ldap-port ::us/integer)
(s/def ::ldap-ssl ::us/boolean)
(s/def ::ldap-starttls ::us/boolean)
(s/def ::ldap-user-query ::us/string)
(s/def ::media-directory ::us/string)
(s/def ::media-uri ::us/string)
(s/def ::profile-bounce-max-age ::dt/duration)
(s/def ::profile-bounce-threshold ::us/integer)
(s/def ::profile-complaint-max-age ::dt/duration)
(s/def ::profile-complaint-threshold ::us/integer)
(s/def ::public-uri ::us/string)
(s/def ::redis-uri ::us/string)
(s/def ::registration-domain-whitelist ::us/set-of-strings)
[:registration-domain-whitelist {:optional true} [::sm/set :string]]
[:email-verify-threshold {:optional true} ::dt/duration]
(s/def ::smtp-default-from ::us/string)
(s/def ::smtp-default-reply-to ::us/string)
(s/def ::smtp-host ::us/string)
(s/def ::smtp-password (s/nilable ::us/string))
(s/def ::smtp-port ::us/integer)
(s/def ::smtp-ssl ::us/boolean)
(s/def ::smtp-tls ::us/boolean)
(s/def ::smtp-username (s/nilable ::us/string))
(s/def ::urepl-host ::us/string)
(s/def ::urepl-port ::us/integer)
(s/def ::prepl-host ::us/string)
(s/def ::prepl-port ::us/integer)
(s/def ::assets-storage-backend ::us/keyword)
(s/def ::storage-assets-fs-directory ::us/string)
(s/def ::storage-assets-s3-bucket ::us/string)
(s/def ::storage-assets-s3-region ::us/keyword)
(s/def ::storage-assets-s3-endpoint ::us/string)
(s/def ::storage-assets-s3-io-threads ::us/integer)
(s/def ::telemetry-uri ::us/string)
(s/def ::telemetry-with-taiga ::us/boolean)
(s/def ::tenant ::us/string)
(s/def ::email-verify-threshold ::dt/duration)
[:github-client-id {:optional true} :string]
[:github-client-secret {:optional true} :string]
[:gitlab-base-uri {:optional true} :string]
[:gitlab-client-id {:optional true} :string]
[:gitlab-client-secret {:optional true} :string]
[:google-client-id {:optional true} :string]
[:google-client-secret {:optional true} :string]
[:oidc-client-id {:optional true} :string]
[:oidc-user-info-source {:optional true} :keyword]
[:oidc-client-secret {:optional true} :string]
[:oidc-base-uri {:optional true} :string]
[:oidc-token-uri {:optional true} :string]
[:oidc-auth-uri {:optional true} :string]
[:oidc-user-uri {:optional true} :string]
[:oidc-jwks-uri {:optional true} :string]
[:oidc-scopes {:optional true} [::sm/set :string]]
[:oidc-roles {:optional true} [::sm/set :string]]
[:oidc-roles-attr {:optional true} :string]
[:oidc-email-attr {:optional true} :string]
[:oidc-name-attr {:optional true} :string]
(s/def ::config
(s/keys :opt-un [::secret-key
::flags
::admins
::deletion-delay
::allow-demo-users
::audit-log-archive-uri
::audit-log-http-handler-concurrency
::auth-token-cookie-name
::auth-token-cookie-max-age
::authenticated-cookie-domain
::database-password
::database-uri
::database-username
::database-readonly
::database-min-pool-size
::database-max-pool-size
::default-blob-version
::default-rpc-rlimit
::email-domain-blacklist
::email-domain-whitelist
::error-report-webhook
::default-executor-parallelism
::scheduled-executor-parallelism
::worker-default-parallelism
::worker-webhook-parallelism
::file-change-snapshot-every
::file-change-snapshot-timeout
::user-feedback-destination
::github-client-id
::github-client-secret
::gitlab-base-uri
::gitlab-client-id
::gitlab-client-secret
::google-client-id
::google-client-secret
::oidc-client-id
::oidc-client-secret
::oidc-user-info-source
::oidc-base-uri
::oidc-token-uri
::oidc-auth-uri
::oidc-user-uri
::oidc-jwks-uri
::oidc-scopes
::oidc-roles-attr
::oidc-email-attr
::oidc-name-attr
::oidc-roles
::host
::http-server-host
::http-server-port
::http-server-max-body-size
::http-server-max-multipart-body-size
::http-server-io-threads
::http-server-worker-threads
::ldap-attrs-email
::ldap-attrs-fullname
::ldap-attrs-username
::ldap-base-dn
::ldap-bind-dn
::ldap-bind-password
::ldap-host
::ldap-port
::ldap-ssl
::ldap-starttls
::ldap-user-query
::local-assets-uri
::media-max-file-size
::profile-bounce-max-age
::profile-bounce-threshold
::profile-complaint-max-age
::profile-complaint-threshold
::public-uri
[:ldap-attrs-email {:optional true} :string]
[:ldap-attrs-fullname {:optional true} :string]
[:ldap-attrs-username {:optional true} :string]
[:ldap-base-dn {:optional true} :string]
[:ldap-bind-dn {:optional true} :string]
[:ldap-bind-password {:optional true} :string]
[:ldap-host {:optional true} :string]
[:ldap-port {:optional true} ::sm/int]
[:ldap-ssl {:optional true} ::sm/boolean]
[:ldap-starttls {:optional true} ::sm/boolean]
[:ldap-user-query {:optional true} :string]
::quotes-teams-per-profile
::quotes-access-tokens-per-profile
::quotes-projects-per-team
::quotes-invitations-per-team
::quotes-profiles-per-team
::quotes-files-per-project
::quotes-files-per-team
::quotes-font-variants-per-team
::quotes-comment-threads-per-file
::quotes-comments-per-file
[:profile-bounce-max-age {:optional true} ::dt/duration]
[:profile-bounce-threshold {:optional true} ::sm/int]
[:profile-complaint-max-age {:optional true} ::dt/duration]
[:profile-complaint-threshold {:optional true} ::sm/int]
::redis-uri
::registration-domain-whitelist
::rpc-rlimit-config
::rpc-climit-config
[:redis-uri {:optional true} ::sm/uri]
::semaphore-process-font
::semaphore-process-image
::semaphore-update-file
::semaphore-auth
[:email-domain-blacklist {:optional true} ::fs/path]
[:email-domain-whitelist {:optional true} ::fs/path]
::smtp-default-from
::smtp-default-reply-to
::smtp-host
::smtp-password
::smtp-port
::smtp-ssl
::smtp-tls
::smtp-username
[:smtp-default-from {:optional true} :string]
[:smtp-default-reply-to {:optional true} :string]
[:smtp-host {:optional true} :string]
[:smtp-password {:optional true} [:maybe :string]]
[:smtp-port {:optional true} ::sm/int]
[:smtp-ssl {:optional true} ::sm/boolean]
[:smtp-tls {:optional true} ::sm/boolean]
[:smtp-username {:optional true} [:maybe :string]]
::urepl-host
::urepl-port
::prepl-host
::prepl-port
[:urepl-host {:optional true} :string]
[:urepl-port {:optional true} ::sm/int]
[:prepl-host {:optional true} :string]
[:prepl-port {:optional true} ::sm/int]
::assets-storage-backend
::storage-assets-fs-directory
::storage-assets-s3-bucket
::storage-assets-s3-region
::storage-assets-s3-endpoint
::storage-assets-s3-io-threads
::telemetry-enabled
::telemetry-uri
::telemetry-referer
::telemetry-with-taiga
::tenant
::email-verify-threshold]))
[:media-directory {:optional true} :string] ;; REVIEW
[:media-uri {:optional true} :string]
[:assets-path {:optional true} :string]
;; Legacy, will be removed in 2.5
[:assets-storage-backend {:optional true} :keyword]
[:storage-assets-fs-directory {:optional true} :string]
[:storage-assets-s3-bucket {:optional true} :string]
[:storage-assets-s3-region {:optional true} :keyword]
[:storage-assets-s3-endpoint {:optional true} ::sm/uri]
[:storage-assets-s3-io-threads {:optional true} ::sm/int]
[:objects-storage-backend {:optional true} :keyword]
[:objects-storage-fs-directory {:optional true} :string]
[:objects-storage-s3-bucket {:optional true} :string]
[:objects-storage-s3-region {:optional true} :keyword]
[:objects-storage-s3-endpoint {:optional true} ::sm/uri]
[:objects-storage-s3-io-threads {:optional true} ::sm/int]]))
(def default-flags
[:enable-backend-api-doc
@@ -367,20 +254,22 @@
{}
env)))
(defn- read-config
[]
(try
(->> (read-env "penpot")
(merge defaults)
(us/conform ::config))
(catch Throwable e
(when (ex/error? e)
(println ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;")
(println "Error on validating configuration:")
(println (some-> e ex-data ex/explain))
(println (ex/explain (ex-data e)))
(println ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"))
(throw e))))
(def decode-config
(sm/decoder schema:config sm/string-transformer))
(def validate-config
(sm/validator schema:config))
(def explain-config
(sm/explainer schema:config))
(defn read-config
"Reads the configuration from enviroment variables and decodes all
known values."
[& {:keys [prefix default] :or {prefix "penpot"}}]
(->> (read-env prefix)
(merge default)
(decode-config)))
(def version
(v/parse (or (some-> (io/resource "version.txt")
@@ -388,10 +277,28 @@
(str/trim))
"%version%")))
(defonce ^:dynamic config (read-config))
(defonce ^:dynamic config (read-config :default default))
(defonce ^:dynamic flags (parse-flags config))
(def deletion-delay
(defn validate!
"Validate the currently loaded configuration data."
[& {:keys [exit-on-error?] :or {exit-on-error? true}}]
(if (validate-config config)
true
(let [explain (explain-config config)]
(println "Error on validating configuration:")
(sm/pretty-explain explain
:variant ::sm/schemaless-explain
:message "Configuration Validation Error")
(flush)
(if exit-on-error?
(System/exit -1)
(ex/raise :type :validation
:code :config-validaton
::sm/explain explain)))))
(defn get-deletion-delay
[]
(or (c/get config :deletion-delay)
(dt/duration {:days 7})))

View File

@@ -11,7 +11,7 @@
[app.common.exceptions :as ex]
[app.common.geom.point :as gpt]
[app.common.logging :as l]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.common.transit :as t]
[app.common.uuid :as uuid]
[app.db.sql :as sql]
@@ -20,7 +20,6 @@
[app.util.time :as dt]
[clojure.java.io :as io]
[clojure.set :as set]
[clojure.spec.alpha :as s]
[integrant.core :as ig]
[next.jdbc :as jdbc]
[next.jdbc.date-time :as jdbc-dt])
@@ -49,27 +48,17 @@
;; Initialization
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::connection-timeout ::us/integer)
(s/def ::max-size ::us/integer)
(s/def ::min-size ::us/integer)
(s/def ::name keyword?)
(s/def ::password ::us/string)
(s/def ::uri ::us/not-empty-string)
(s/def ::username ::us/string)
(s/def ::validation-timeout ::us/integer)
(s/def ::read-only? ::us/boolean)
(s/def ::pool-options
(s/keys :opt [::uri
::name
::min-size
::max-size
::connection-timeout
::validation-timeout
::username
::password
::mtx/metrics
::read-only?]))
(def ^:private schema:pool-options
[:map {:title "pool-options"}
[::connect-timeout {:optional true} ::sm/int]
[::max-size {:optional true} ::sm/int]
[::min-size {:optional true} ::sm/int]
[::name {:optional true} :keyword]
[::uri {:optional true} ::sm/uri]
[::password {:optional true} :string]
[::username {:optional true} :string]
[::validation-timeout {:optional true} ::sm/int]
[::read-only {:optional true} ::sm/boolean]])
(def defaults
{::name :main
@@ -79,27 +68,26 @@
::validation-timeout 10000
::idle-timeout 120000 ; 2min
::max-lifetime 1800000 ; 30m
::read-only? false})
::read-only false})
(defmethod ig/prep-key ::pool
[_ cfg]
(merge defaults (d/without-nils cfg)))
;; Don't validate here, just validate that a map is received.
(defmethod ig/pre-init-spec ::pool [_] ::pool-options)
(defmethod ig/assert-key ::pool
[_ options]
(assert (sm/check schema:pool-options options)))
(defmethod ig/init-key ::pool
[_ {:keys [::uri ::read-only?] :as cfg}]
(when uri
(l/info :hint "initialize connection pool"
:name (d/name (::name cfg))
:uri uri
:read-only read-only?
:with-credentials (and (contains? cfg ::username)
(contains? cfg ::password))
:min-size (::min-size cfg)
:max-size (::max-size cfg))
(create-pool cfg)))
[_ cfg]
(let [{:keys [::uri ::read-only] :as cfg}
(merge defaults cfg)]
(when uri
(l/info :hint "initialize connection pool"
:name (d/name (::name cfg))
:uri (str uri)
:read-only read-only
:credentials (and (contains? cfg ::username)
(contains? cfg ::password))
:min-size (::min-size cfg)
:max-size (::max-size cfg))
(create-pool cfg))))
(defmethod ig/halt-key! ::pool
[_ pool]
@@ -115,13 +103,15 @@
"SET idle_in_transaction_session_timeout = 300000;"))
(defn- create-datasource-config
[{:keys [::mtx/metrics ::uri] :as cfg}]
[{:keys [::uri] :as cfg}]
;; (app.common.pprint/pprint cfg)
(let [config (HikariConfig.)]
(doto config
(.setJdbcUrl (str "jdbc:" uri))
(.setPoolName (d/name (::name cfg)))
(.setAutoCommit true)
(.setReadOnly (::read-only? cfg))
(.setReadOnly (::read-only cfg))
(.setConnectionTimeout (::connection-timeout cfg))
(.setValidationTimeout (::validation-timeout cfg))
(.setIdleTimeout (::idle-timeout cfg))
@@ -132,8 +122,8 @@
(.setInitializationFailTimeout -1))
;; When metrics namespace is provided
(when metrics
(->> (::mtx/registry metrics)
(when-let [instance (::mtx/metrics cfg)]
(->> (mtx/get-registry instance)
(PrometheusMetricsTrackerFactory.)
(.setMetricsTrackerFactory config)))
@@ -150,10 +140,22 @@
[conn]
(instance? Connection conn))
(s/def ::conn some?)
(s/def ::nilable-pool (s/nilable ::pool))
(s/def ::pool pool?)
(s/def ::pool-or-conn some?)
(defn connectable?
[o]
(or (connection? o)
(pool? o)))
(sm/register!
{:type ::conn
:pred connection?})
(sm/register!
{:type ::connectable
:pred connectable?})
(sm/register!
{:type ::pool
:pred pool?})
(defn closed?
[pool]
@@ -407,6 +409,7 @@
(ex/raise :type :not-found
:code :object-not-found
:table table
:params params
:hint "database object not found"))
row))

View File

@@ -7,19 +7,17 @@
(ns app.email
"Main api for send emails."
(:require
[app.common.data.macros :as dm]
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.pprint :as pp]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.config :as cf]
[app.db :as db]
[app.db.sql :as sql]
[app.email.invite-to-team :as-alias email.invite-to-team]
[app.metrics :as mtx]
[app.util.template :as tmpl]
[app.worker :as wrk]
[clojure.java.io :as io]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig])
(:import
@@ -149,9 +147,27 @@
"mail.smtp.timeout" timeout
"mail.smtp.connectiontimeout" timeout}))
(def ^:private schema:smtp-config
[:map
[::username {:optional true} :string]
[::password {:optional true} :string]
[::tls {:optional true} ::sm/boolean]
[::ssl {:optional true} ::sm/boolean]
[::host {:optional true} :string]
[::port {:optional true} ::sm/int]
[::default-from {:optional true} :string]
[::default-reply-to {:optional true} :string]])
(def valid-smtp-config?
(sm/check-fn schema:smtp-config))
(defn- create-smtp-session
^Session
[cfg]
(dm/assert!
"expected valid smtp config"
(valid-smtp-config? cfg))
(let [props (opts->props cfg)]
(Session/getInstance props)))
@@ -201,50 +217,47 @@
[{:type "text/html"
:content html}]))}))
(s/def ::priority #{:high :low})
(s/def ::to (s/or :single ::us/email
:multi (s/coll-of ::us/email)))
(s/def ::from ::us/email)
(s/def ::reply-to ::us/email)
(s/def ::lang string?)
(s/def ::extra-data ::us/string)
(def ^:private schema:context
[:map
[:to [:or ::sm/email [::sm/vec ::sm/email]]]
[:reply-to {:optional true} ::sm/email]
[:from {:optional true} ::sm/email]
[:lang {:optional true} ::sm/text]
[:priority {:optional true} [:enum :high :low]]
[:extra-data {:optional true} ::sm/text]])
(s/def ::context
(s/keys :req-un [::to]
:opt-un [::reply-to ::from ::lang ::priority ::extra-data]))
(def ^:private valid-context?
(sm/validator schema:context))
(defn template-factory
([id] (template-factory id {}))
([id extra-context]
(s/assert keyword? id)
(fn [context]
(us/verify ::context context)
(when-let [spec (s/get-spec id)]
(s/assert spec context))
[& {:keys [id schema]}]
(assert (keyword? id) "id should be provided and it should be a keyword")
(let [check-fn (if schema
(sm/check-fn schema)
(constantly nil))]
(fn [context]
(assert (valid-context? context) "expected a valid context")
(check-fn context)
(let [context (merge (if (fn? extra-context)
(extra-context)
extra-context)
context)
email (build-email-template id context)]
(when-not email
(ex/raise :type :internal
:code :email-template-does-not-exists
:hint "seems like the template is wrong or does not exists."
:context {:id id}))
(cond-> (assoc email :id (name id))
(:extra-data context)
(assoc :extra-data (:extra-data context))
(let [email (build-email-template id context)]
(when-not email
(ex/raise :type :internal
:code :email-template-does-not-exists
:hint "seems like the template is wrong or does not exists."
:template-id id))
(:from context)
(assoc :from (:from context))
(cond-> (assoc email :id (name id))
(:extra-data context)
(assoc :extra-data (:extra-data context))
(:reply-to context)
(assoc :reply-to (:reply-to context))
(:from context)
(assoc :from (:from context))
(:to context)
(assoc :to (:to context)))))))
(:reply-to context)
(assoc :reply-to (:reply-to context))
(:to context)
(assoc :to (:to context)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PUBLIC HIGH-LEVEL API
@@ -258,7 +271,8 @@
"Schedule an already defined email to be sent using asynchronously
using worker task."
[{:keys [::conn ::factory] :as context}]
(us/verify some? conn)
(assert (db/connection? conn) "expected a valid database connection")
(let [email (if factory
(factory context)
(dissoc context ::conn))]
@@ -273,32 +287,8 @@
;; SENDMAIL FN / TASK HANDLER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::username ::cf/smtp-username)
(s/def ::password ::cf/smtp-password)
(s/def ::tls ::cf/smtp-tls)
(s/def ::ssl ::cf/smtp-ssl)
(s/def ::host ::cf/smtp-host)
(s/def ::port ::cf/smtp-port)
(s/def ::default-reply-to ::cf/smtp-default-reply-to)
(s/def ::default-from ::cf/smtp-default-from)
(s/def ::smtp-config
(s/keys :opt [::username
::password
::tls
::ssl
::host
::port
::default-from
::default-reply-to]))
(declare send-to-logger!)
(s/def ::sendmail fn?)
(defmethod ig/pre-init-spec ::sendmail [_]
(s/spec ::smtp-config))
(defmethod ig/init-key ::sendmail
[_ cfg]
(fn [params]
@@ -315,19 +305,18 @@
(l/dbg :hint "sendmail"
:id (:id params)
:to (:to params)
:subject (str/trim (:subject params))
:body (str/join "," (map :type (:body params))))
:subject (str/trim (:subject params)))
(.sendMessage ^Transport transport
^MimeMessage message
(.getAllRecipients message))))))
(when (or (contains? cf/flags :log-emails)
(not (contains? cf/flags :smtp)))
(when (contains? cf/flags :log-emails)
(send-to-logger! cfg params))))
(defmethod ig/pre-init-spec ::handler [_]
(s/keys :req [::sendmail ::mtx/metrics]))
(defmethod ig/assert-key ::handler
[_ params]
(assert (fn? (::sendmail params)) "expected valid sendmail handler"))
(defmethod ig/init-key ::handler
[_ {:keys [::sendmail]}]
@@ -354,52 +343,113 @@
;; EMAIL FACTORIES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::subject ::us/string)
(s/def ::content ::us/string)
(s/def ::feedback
(s/keys :req-un [::subject ::content]))
(def ^:private schema:feedback
[:map
[:subject ::sm/text]
[:content ::sm/text]])
(def feedback
"A profile feedback email."
(template-factory ::feedback))
(template-factory
:id ::feedback
:schema schema:feedback))
(s/def ::name ::us/string)
(s/def ::register
(s/keys :req-un [::name]))
(def ^:private schema:register
[:map [:name ::sm/text]])
(def register
"A new profile registration welcome email."
(template-factory ::register))
(template-factory
:id ::register
:schema schema:register))
(s/def ::token ::us/string)
(s/def ::password-recovery
(s/keys :req-un [::name ::token]))
(def ^:private schema:password-recovery
[:map
[:name ::sm/text]
[:token ::sm/text]])
(def password-recovery
"A password recovery notification email."
(template-factory ::password-recovery))
(template-factory
:id ::password-recovery
:schema schema:password-recovery))
(s/def ::pending-email ::us/email)
(s/def ::change-email
(s/keys :req-un [::name ::pending-email ::token]))
(def ^:private schema:change-email
[:map
[:name ::sm/text]
[:pending-email ::sm/email]
[:token ::sm/text]])
(def change-email
"Password change confirmation email"
(template-factory ::change-email))
(template-factory
:id ::change-email
:schema schema:change-email))
(s/def ::email.invite-to-team/invited-by ::us/string)
(s/def ::email.invite-to-team/team ::us/string)
(s/def ::email.invite-to-team/token ::us/string)
(s/def ::invite-to-team
(s/keys :req-un [::email.invite-to-team/invited-by
::email.invite-to-team/token
::email.invite-to-team/team]))
(def ^:private schema:invite-to-team
[:map
[:invited-by ::sm/text]
[:team ::sm/text]
[:token ::sm/text]])
(def invite-to-team
"Teams member invitation email."
(template-factory ::invite-to-team))
(template-factory
:id ::invite-to-team
:schema schema:invite-to-team))
(def ^:private schema:join-team
[:map
[:invited-by ::sm/text]
[:team ::sm/text]
[:team-id ::sm/uuid]])
(def join-team
"Teams member joined after request email."
(template-factory
:id ::join-team
:schema schema:join-team))
(def ^:private schema:request-file-access
[:map
[:requested-by ::sm/text]
[:requested-by-email ::sm/text]
[:team-name ::sm/text]
[:team-id ::sm/uuid]
[:file-name ::sm/text]
[:file-id ::sm/uuid]
[:page-id ::sm/uuid]])
(def request-file-access
"File access request email."
(template-factory
:id ::request-file-access
:schema schema:request-file-access))
(def request-file-access-yourpenpot
"File access on Your Penpot request email."
(template-factory
:id ::request-file-access-yourpenpot
:schema schema:request-file-access))
(def request-file-access-yourpenpot-view
"File access on Your Penpot view mode request email."
(template-factory
:id ::request-file-access-yourpenpot-view
:schema schema:request-file-access))
(def ^:private schema:request-team-access
[:map
[:requested-by ::sm/text]
[:requested-by-email ::sm/text]
[:team-name ::sm/text]
[:team-id ::sm/uuid]])
(def request-team-access
"Team access request email."
(template-factory
:id ::request-team-access
:schema schema:request-team-access))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; BOUNCE/COMPLAINS HELPERS

View File

@@ -41,6 +41,7 @@
[app.common.types.shape.path :as ctsp]
[app.common.types.shape.text :as ctsx]
[app.common.uuid :as uuid]
[app.config :as cf]
[app.db :as db]
[app.db.sql :as sql]
[app.features.fdata :as fdata]
@@ -62,6 +63,7 @@
[datoteka.io :as io]
[promesa.util :as pu]))
(def ^:dynamic *stats*
"A dynamic var for setting up state for collect stats globally."
nil)
@@ -113,7 +115,7 @@
(sm/lazy-validator ::ctc/color))
(def valid-fill?
(sm/lazy-validator ::cts/fill))
(sm/lazy-validator cts/schema:fill))
(def valid-stroke?
(sm/lazy-validator ::cts/stroke))
@@ -134,10 +136,10 @@
(sm/lazy-validator ::ctc/rgb-color))
(def valid-shape-points?
(sm/lazy-validator ::cts/points))
(sm/lazy-validator cts/schema:points))
(def valid-image-attrs?
(sm/lazy-validator ::cts/image-attrs))
(sm/lazy-validator cts/schema:image-attrs))
(def valid-column-grid-params?
(sm/lazy-validator ::ctg/column-params))
@@ -1297,7 +1299,7 @@
(let [[mtype data] (parse-datauri href)
size (alength ^bytes data)
path (tmp/tempfile :prefix "penpot.media.download.")
written (io/write-to-file! data path :size size)]
written (io/write* path data :size size)]
(when (not= written size)
(ex/raise :type :internal
@@ -1380,7 +1382,9 @@
(defn get-optimized-svg
[sid]
(let [svg-text (get-sobject-content sid)
svg-text (svgo/optimize *system* svg-text)]
svg-text (if (contains? cf/flags :backend-svgo)
(svgo/optimize *system* svg-text)
svg-text)]
(csvg/parse svg-text)))
(def base-path "/data/cache")
@@ -1483,11 +1487,6 @@
:file-id (str (:id fdata))
:id (str (:id mobj)))
(instance? org.graalvm.polyglot.PolyglotException cause)
(l/inf :hint "skip processing media object: invalid svg found"
:file-id (str (:id fdata))
:id (str (:id mobj)))
(= (:type edata) :not-found)
(l/inf :hint "skip processing media object: underlying object does not exist"
:file-id (str (:id fdata))
@@ -1742,12 +1741,12 @@
:validate validate?
:skip-on-graphic-error skip-on-graphic-error?)
(db/tx-run! (update system ::sto/storage media/configure-assets-storage)
(db/tx-run! system
(fn [system]
(binding [*system* system]
(when (string? label)
(fsnap/take-file-snapshot! system {:file-id file-id
:label (str "migration/" label)}))
(fsnap/create-file-snapshot! system nil file-id (str "migration/" label)))
(let [file (get-file system file-id)
file (process-file! system file :validate? validate?)]

View File

@@ -12,10 +12,19 @@
[app.common.logging :as l]
[app.db :as db]
[app.db.sql :as-alias sql]
[app.storage :as sto]
[app.util.blob :as blob]
[app.util.objects-map :as omap]
[app.util.pointer-map :as pmap]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OFFLOAD
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn offloaded?
[file]
(= "objects-storage" (:data-backend file)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OBJECTS-MAP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -55,31 +64,45 @@
;; POINTER-MAP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn get-file-data
"Get file data given a file instance."
[system file]
(if (offloaded? file)
(let [storage (sto/resolve system ::db/reuse-conn true)]
(->> (sto/get-object storage (:data-ref-id file))
(sto/get-object-bytes storage)))
(:data file)))
(defn resolve-file-data
[system file]
(let [data (get-file-data system file)]
(assoc file :data data)))
(defn load-pointer
"A database loader pointer helper"
[system file-id id]
(let [{:keys [content]} (db/get system :file-data-fragment
{:id id :file-id file-id}
{::sql/columns [:content]
::db/check-deleted false})]
(let [fragment (db/get* system :file-data-fragment
{:id id :file-id file-id}
{::sql/columns [:data :data-backend :data-ref-id :id]})]
(l/trc :hint "load pointer"
:file-id (str file-id)
:id (str id)
:found (some? content))
:found (some? fragment))
(when-not content
(when-not fragment
(ex/raise :type :internal
:code :fragment-not-found
:hint "fragment not found"
:file-id file-id
:fragment-id id))
(blob/decode content)))
(let [data (get-file-data system fragment)]
;; FIXME: conditional thread scheduling for decoding big objects
(blob/decode data))))
(defn persist-pointers!
"Given a database connection and the final file-id, persist all
pointers to the underlying storage (the database)."
"Persist all currently tracked pointer objects"
[system file-id]
(let [conn (db/get-connection system)]
(doseq [[id item] @pmap/*tracked*]
@@ -89,7 +112,7 @@
(db/insert! conn :file-data-fragment
{:id id
:file-id file-id
:content content}))))))
:data content}))))))
(defn process-pointers
"Apply a function to all pointers on the file. Usuly used for

View File

@@ -9,6 +9,7 @@
[app.auth.oidc :as-alias oidc]
[app.common.data :as d]
[app.common.logging :as l]
[app.common.schema :as sm]
[app.common.transit :as t]
[app.db :as-alias db]
[app.http.access-token :as actoken]
@@ -24,14 +25,13 @@
[app.rpc :as-alias rpc]
[app.rpc.doc :as-alias rpc.doc]
[app.setup :as-alias setup]
[clojure.spec.alpha :as s]
[integrant.core :as ig]
[promesa.exec :as px]
[reitit.core :as r]
[reitit.middleware :as rr]
[ring.request :as rreq]
[ring.response :as-alias rres]
[yetti.adapter :as yt]))
[yetti.adapter :as yt]
[yetti.request :as yreq]
[yetti.response :as-alias yres]))
(declare router-handler)
@@ -39,31 +39,28 @@
;; HTTP SERVER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::handler fn?)
(s/def ::router some?)
(s/def ::port integer?)
(s/def ::host string?)
(s/def ::name string?)
(def default-params
{::port 6060
::host "0.0.0.0"
::max-body-size (* 1024 1024 30) ; default 30 MiB
::max-multipart-body-size (* 1024 1024 120)}) ; default 120 MiB
(s/def ::max-body-size integer?)
(s/def ::max-multipart-body-size integer?)
(s/def ::io-threads integer?)
(defmethod ig/expand-key ::server
[k v]
{k (merge default-params (d/without-nils v))})
(defmethod ig/prep-key ::server
[_ cfg]
(merge {::port 6060
::host "0.0.0.0"
::max-body-size (* 1024 1024 30) ; default 30 MiB
::max-multipart-body-size (* 1024 1024 120)} ; default 120 MiB
(d/without-nils cfg)))
(def ^:private schema:server-params
[:map
[::port ::sm/int]
[::host ::sm/text]
[::max-body-size {:optional true} ::sm/int]
[::max-multipart-body-size {:optional true} ::sm/int]
[::router {:optional true} [:fn r/router?]]
[::handler {:optional true} ::sm/fn]])
(defmethod ig/pre-init-spec ::server [_]
(s/keys :req [::port ::host]
:opt [::max-body-size
::max-multipart-body-size
::router
::handler
::io-threads]))
(defmethod ig/assert-key ::server
[_ params]
(assert (sm/check schema:server-params params)))
(defmethod ig/init-key ::server
[_ {:keys [::handler ::router ::host ::port] :as cfg}]
@@ -100,12 +97,12 @@
(defn- not-found-handler
[_]
{::rres/status 404})
{::yres/status 404})
(defn- router-handler
[router]
(letfn [(resolve-handler [request]
(if-let [match (r/match-by-path router (rreq/path request))]
(if-let [match (r/match-by-path router (yreq/path request))]
(let [params (:path-params match)
result (:result match)
handler (or (:handler result) not-found-handler)
@@ -114,11 +111,11 @@
(partial not-found-handler request)))
(on-error [cause request]
(let [{:keys [::rres/body] :as response} (errors/handle cause request)]
(let [{:keys [::yres/body] :as response} (errors/handle cause request)]
(cond-> response
(map? body)
(-> (update ::rres/headers assoc "content-type" "application/transit+json")
(assoc ::rres/body (t/encode-str body {:type :json-verbose}))))))]
(-> (update ::yres/headers assoc "content-type" "application/transit+json")
(assoc ::yres/body (t/encode-str body {:type :json-verbose}))))))]
(fn [request]
(let [handler (resolve-handler request)]
@@ -131,18 +128,26 @@
;; HTTP ROUTER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmethod ig/pre-init-spec ::router [_]
(s/keys :req [::session/manager
::ws/routes
::rpc/routes
::rpc.doc/routes
::oidc/routes
::setup/props
::assets/routes
::debug/routes
::db/pool
::mtx/routes
::awsns/routes]))
(def ^:private schema:routes
[:vector :any])
(def ^:private schema:router-params
[:map
[::ws/routes schema:routes]
[::rpc/routes schema:routes]
[::rpc.doc/routes schema:routes]
[::oidc/routes schema:routes]
[::assets/routes schema:routes]
[::debug/routes schema:routes]
[::mtx/routes schema:routes]
[::awsns/routes schema:routes]
::session/manager
::setup/props
::db/pool])
(defmethod ig/assert-key ::router
[_ params]
(assert (sm/check schema:router-params params)))
(defmethod ig/init-key ::router
[_ cfg]

View File

@@ -12,13 +12,13 @@
[app.main :as-alias main]
[app.setup :as-alias setup]
[app.tokens :as tokens]
[ring.request :as rreq]))
[yetti.request :as yreq]))
(def header-re #"^Token\s+(.*)")
(defn- get-token
[request]
(some->> (rreq/get-header request "authorization")
(some->> (yreq/get-header request "authorization")
(re-matches header-re)
(second)))

View File

@@ -9,14 +9,12 @@
(:require
[app.common.data :as d]
[app.common.exceptions :as ex]
[app.common.spec :as us]
[app.common.uri :as u]
[app.db :as db]
[app.storage :as sto]
[app.util.time :as dt]
[clojure.spec.alpha :as s]
[integrant.core :as ig]
[ring.response :as-alias rres]))
[yetti.response :as-alias yres]))
(def ^:private cache-max-age
(dt/duration {:hours 24}))
@@ -37,8 +35,8 @@
(defn- serve-object-from-s3
[{:keys [::sto/storage] :as cfg} obj]
(let [{:keys [host port] :as url} (sto/get-object-url storage obj {:max-age signature-max-age})]
{::rres/status 307
::rres/headers {"location" (str url)
{::yres/status 307
::yres/headers {"location" (str url)
"x-host" (cond-> host port (str ":" port))
"x-mtype" (-> obj meta :content-type)
"cache-control" (str "max-age=" (inst-ms cache-max-age))}}))
@@ -51,17 +49,16 @@
headers {"x-accel-redirect" (:path purl)
"content-type" (:content-type mdata)
"cache-control" (str "max-age=" (inst-ms cache-max-age))}]
{::rres/status 204
::rres/headers headers}))
{::yres/status 204
::yres/headers headers}))
(defn- serve-object
"Helper function that returns the appropriate response depending on
the storage object backend type."
[{:keys [::sto/storage] :as cfg} {:keys [backend] :as obj}]
(let [backend (sto/resolve-backend storage backend)]
(case (::sto/type backend)
:s3 (serve-object-from-s3 cfg obj)
:fs (serve-object-from-fs cfg obj))))
[cfg {:keys [backend] :as obj}]
(case backend
(:s3 :assets-s3) (serve-object-from-s3 cfg obj)
(:fs :assets-fs) (serve-object-from-fs cfg obj)))
(defn objects-handler
"Handler that servers storage objects by id."
@@ -70,7 +67,7 @@
obj (sto/get-object storage id)]
(if obj
(serve-object cfg obj)
{::rres/status 404})))
{::yres/status 404})))
(defn- generic-handler
"A generic handler helper/common code for file-media based handlers."
@@ -81,7 +78,7 @@
sobj (sto/get-object storage (kf mobj))]
(if sobj
(serve-object cfg sobj)
{::rres/status 404})))
{::yres/status 404})))
(defn file-objects-handler
"Handler that serves storage objects by file media id."
@@ -96,11 +93,10 @@
;; --- Initialization
(s/def ::path ::us/string)
(s/def ::routes vector?)
(defmethod ig/pre-init-spec ::routes [_]
(s/keys :req [::sto/storage ::path]))
(defmethod ig/assert-key ::routes
[_ params]
(assert (sto/valid-storage? (::sto/storage params)) "expected valid storage instance")
(assert (string? (::path params))))
(defmethod ig/init-key ::routes
[_ cfg]

View File

@@ -10,6 +10,7 @@
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.pprint :as pp]
[app.common.schema :as sm]
[app.db :as db]
[app.db.sql :as sql]
[app.http.client :as http]
@@ -18,29 +19,29 @@
[app.tokens :as tokens]
[app.worker :as-alias wrk]
[clojure.data.json :as j]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig]
[promesa.exec :as px]
[ring.request :as rreq]
[ring.response :as-alias rres]))
[yetti.request :as yreq]
[yetti.response :as-alias yres]))
(declare parse-json)
(declare handle-request)
(declare parse-notification)
(declare process-report)
(defmethod ig/pre-init-spec ::routes [_]
(s/keys :req [::http/client
::setup/props
::db/pool]))
(defmethod ig/assert-key ::routes
[_ params]
(assert (http/client? (::http/client params)) "expect a valid http client")
(assert (sm/valid? ::setup/props (::setup/props params)) "expected valid setup props")
(assert (db/pool? (::db/pool params)) "expect valid database pool"))
(defmethod ig/init-key ::routes
[_ cfg]
(letfn [(handler [request]
(let [data (-> request rreq/body slurp)]
(let [data (-> request yreq/body slurp)]
(px/run! :vthread (partial handle-request cfg data)))
{::rres/status 200})]
{::yres/status 200})]
["/sns" {:handler handler
:allowed-methods #{:post}}]))

View File

@@ -7,20 +7,20 @@
(ns app.http.client
"Http client abstraction layer."
(:require
[app.common.spec :as us]
[clojure.spec.alpha :as s]
[app.common.schema :as sm]
[integrant.core :as ig]
[java-http-clj.core :as http]
[promesa.core :as p])
(:import
java.net.http.HttpClient))
(s/def ::client #(instance? HttpClient %))
(s/def ::client-holder
(s/keys :req [::client]))
(defn client?
[o]
(instance? HttpClient o))
(defmethod ig/pre-init-spec ::client [_]
(s/keys :req []))
(sm/register!
{:type ::client
:pred client?})
(defmethod ig/init-key ::client
[_ _]
@@ -30,7 +30,7 @@
(defn send!
([client req] (send! client req {}))
([client req {:keys [response-type sync?] :or {response-type :string sync? false}}]
(us/assert! ::client client)
(assert (client? client) "expected valid http client")
(if sync?
(http/send req {:client client :as response-type})
(try
@@ -54,9 +54,10 @@
"A convencience toplevel function for gradual migration to a new API
convention."
([cfg-or-client request]
(let [client (resolve-client cfg-or-client)]
(let [client (resolve-client cfg-or-client)
request (update request :uri str)]
(send! client request {:sync? true})))
([cfg-or-client request options]
(let [client (resolve-client cfg-or-client)]
(let [client (resolve-client cfg-or-client)
request (update request :uri str)]
(send! client request (merge {:sync? true} options)))))

View File

@@ -26,15 +26,14 @@
[app.util.blob :as blob]
[app.util.template :as tmpl]
[app.util.time :as dt]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[datoteka.io :as io]
[emoji.core :as emj]
[integrant.core :as ig]
[markdown.core :as md]
[markdown.transformers :as mdt]
[ring.request :as rreq]
[ring.response :as rres]))
[yetti.request :as yreq]
[yetti.response :as yres]))
;; (selmer.parser/cache-off!)
@@ -44,10 +43,10 @@
(defn index-handler
[_cfg _request]
{::rres/status 200
::rres/headers {"content-type" "text/html"}
::rres/body (-> (io/resource "app/templates/debug.tmpl")
(tmpl/render {}))})
{::yres/status 200
::yres/headers {"content-type" "text/html"}
::yres/body (-> (io/resource "app/templates/debug.tmpl")
(tmpl/render {:version (:full cf/version)}))})
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; FILE CHANGES
@@ -56,17 +55,17 @@
(defn prepare-response
[body]
(let [headers {"content-type" "application/transit+json"}]
{::rres/status 200
::rres/body body
::rres/headers headers}))
{::yres/status 200
::yres/body body
::yres/headers headers}))
(defn prepare-download-response
[body filename]
(let [headers {"content-disposition" (str "attachment; filename=" filename)
"content-type" "application/octet-stream"}]
{::rres/status 200
::rres/body body
::rres/headers headers}))
{::yres/status 200
::yres/body body
::yres/headers headers}))
(def sql:retrieve-range-of-changes
"select revn, changes from file_change where file_id=? and revn >= ? and revn <= ? order by revn")
@@ -108,8 +107,8 @@
(db/update! conn :file
{:data data}
{:id file-id})
{::rres/status 201
::rres/body "OK CREATED"})))
{::yres/status 201
::yres/body "OK CREATED"})))
:else
(prepare-response (blob/decode data))))))
@@ -123,7 +122,7 @@
[{:keys [::db/pool]} {:keys [::session/profile-id params] :as request}]
(let [profile (profile/get-profile pool profile-id)
project-id (:default-project-id profile)
data (some-> params :file :path io/read-as-bytes)]
data (some-> params :file :path io/read*)]
(if (and data project-id)
(let [fname (str "Imported file *: " (dt/now))
@@ -138,8 +137,8 @@
{:data data
:deleted-at nil}
{:id file-id})
{::rres/status 200
::rres/body "OK UPDATED"})
{::yres/status 200
::yres/body "OK UPDATED"})
(db/run! pool (fn [{:keys [::db/conn] :as cfg}]
(create-file cfg {:id file-id
@@ -149,15 +148,15 @@
(db/update! conn :file
{:data data}
{:id file-id})
{::rres/status 201
::rres/body "OK CREATED"}))))
{::yres/status 201
::yres/body "OK CREATED"}))))
{::rres/status 500
::rres/body "ERROR"})))
{::yres/status 500
::yres/body "ERROR"})))
(defn file-data-handler
[cfg request]
(case (rreq/method request)
(case (yreq/method request)
:get (retrieve-file-data cfg request)
:post (upload-file-data cfg request)
(ex/raise :type :http
@@ -238,12 +237,12 @@
1 (render-template-v1 report)
2 (render-template-v2 report)
3 (render-template-v3 report))]
{::rres/status 200
::rres/body result
::rres/headers {"content-type" "text/html; charset=utf-8"
{::yres/status 200
::yres/body result
::yres/headers {"content-type" "text/html; charset=utf-8"
"x-robots-tag" "noindex"}})
{::rres/status 404
::rres/body "not found"})))
{::yres/status 404
::yres/body "not found"})))
(def sql:error-reports
"SELECT id, created_at,
@@ -256,10 +255,10 @@
[{:keys [::db/pool]} _request]
(let [items (->> (db/exec! pool [sql:error-reports])
(map #(update % :created-at dt/format-instant :rfc1123)))]
{::rres/status 200
::rres/body (-> (io/resource "app/templates/error-list.tmpl")
{::yres/status 200
::yres/body (-> (io/resource "app/templates/error-list.tmpl")
(tmpl/render {:items items}))
::rres/headers {"content-type" "text/html; charset=utf-8"
::yres/headers {"content-type" "text/html; charset=utf-8"
"x-robots-tag" "noindex"}}))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -295,15 +294,16 @@
cfg (assoc cfg
::bf.v1/overwrite false
::bf.v1/profile-id profile-id
::bf.v1/project-id project-id)]
(bf.v1/import-files! cfg path)
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body "OK CLONED"})
::bf.v1/project-id project-id
::bf.v1/input path)]
(bf.v1/import-files! cfg)
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body "OK CLONED"})
{::rres/status 200
::rres/body (io/input-stream path)
::rres/headers {"content-type" "application/octet-stream"
{::yres/status 200
::yres/body (io/input-stream path)
::yres/headers {"content-type" "application/octet-stream"
"content-disposition" (str "attachmen; filename=" (first file-ids) ".penpot")}}))))
@@ -329,11 +329,12 @@
::bf.v1/overwrite overwrite?
::bf.v1/migrate migrate?
::bf.v1/profile-id profile-id
::bf.v1/project-id project-id)]
(bf.v1/import-files! cfg path)
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body "OK"})))
::bf.v1/project-id project-id
::bf.v1/input path)]
(bf.v1/import-files! cfg)
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body "OK"})))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ACTIONS
@@ -363,34 +364,34 @@
(db/update! conn :profile {:is-blocked true} {:id (:id profile)})
(db/delete! conn :http-session {:profile-id (:id profile)})
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body (str/ffmt "PROFILE '%' BLOCKED" (:email profile))})
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body (str/ffmt "PROFILE '%' BLOCKED" (:email profile))})
(contains? params :unblock)
(do
(db/update! conn :profile {:is-blocked false} {:id (:id profile)})
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body (str/ffmt "PROFILE '%' UNBLOCKED" (:email profile))})
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body (str/ffmt "PROFILE '%' UNBLOCKED" (:email profile))})
(contains? params :resend)
(if (:is-blocked profile)
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body "PROFILE ALREADY BLOCKED"}
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body "PROFILE ALREADY BLOCKED"}
(do
(#'auth/send-email-verification! cfg profile)
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body (str/ffmt "RESENDED FOR '%'" (:email profile))}))
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body (str/ffmt "RESENDED FOR '%'" (:email profile))}))
:else
(do
(db/update! conn :profile {:is-active true} {:id (:id profile)})
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body (str/ffmt "PROFILE '%' ACTIVATED" (:email profile))}))))))
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body (str/ffmt "PROFILE '%' ACTIVATED" (:email profile))}))))))
(defn- reset-file-version
@@ -415,9 +416,9 @@
(db/tx-run! cfg srepl/process-file! file-id #(assoc % :version version))
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body "OK"}))
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body "OK"}))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -429,13 +430,13 @@
[{:keys [::db/pool]} _]
(try
(db/exec-one! pool ["select count(*) as count from server_prop;"])
{::rres/status 200
::rres/body "OK"}
{::yres/status 200
::yres/body "OK"}
(catch Throwable cause
(l/warn :hint "unable to execute query on health handler"
:cause cause)
{::rres/status 503
::rres/body "KO"})))
{::yres/status 503
::yres/body "KO"})))
(defn changelog-handler
[_ _]
@@ -444,11 +445,11 @@
(md->html [text]
(md/md-to-html-string text :replacement-transformers (into [transform-emoji] mdt/transformer-vector)))]
(if-let [clog (io/resource "changelog.md")]
{::rres/status 200
::rres/headers {"content-type" "text/html; charset=utf-8"}
::rres/body (-> clog slurp md->html)}
{::rres/status 404
::rres/body "NOT FOUND"})))
{::yres/status 200
::yres/headers {"content-type" "text/html; charset=utf-8"}
::yres/body (-> clog slurp md->html)}
{::yres/status 404
::yres/body "NOT FOUND"})))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INIT
@@ -471,8 +472,10 @@
(ex/raise :type :authentication
:code :only-admins-allowed)))))})
(defmethod ig/pre-init-spec ::routes [_]
(s/keys :req [::db/pool ::session/manager]))
(defmethod ig/assert-key ::routes
[_ params]
(assert (db/pool? (::db/pool params)) "expected a valid database pool")
(assert (session/manager? (::session/manager params)) "expected a valid session manager"))
(defmethod ig/init-key ::routes
[_ {:keys [::db/pool] :as cfg}]

View File

@@ -16,8 +16,8 @@
[app.http.session :as-alias session]
[app.util.inet :as inet]
[clojure.spec.alpha :as s]
[ring.request :as rreq]
[ring.response :as rres]))
[yetti.request :as yreq]
[yetti.response :as yres]))
(defn request->context
"Extracts error report relevant context data from request."
@@ -29,10 +29,10 @@
{:request/path (:path request)
:request/method (:method request)
:request/params (:params request)
:request/user-agent (rreq/get-header request "user-agent")
:request/user-agent (yreq/get-header request "user-agent")
:request/ip-addr (inet/parse-request request)
:request/profile-id (:uid claims)
:version/frontend (or (rreq/get-header request "x-frontend-version") "unknown")
:version/frontend (or (yreq/get-header request "x-frontend-version") "unknown")
:version/backend (:full cf/version)}))
@@ -46,34 +46,34 @@
(defmethod handle-error :authentication
[err _ _]
{::rres/status 401
::rres/body (ex-data err)})
{::yres/status 401
::yres/body (ex-data err)})
(defmethod handle-error :authorization
[err _ _]
{::rres/status 403
::rres/body (ex-data err)})
{::yres/status 403
::yres/body (ex-data err)})
(defmethod handle-error :restriction
[err _ _]
(let [{:keys [code] :as data} (ex-data err)]
(if (= code :method-not-allowed)
{::rres/status 405
::rres/body data}
{::rres/status 400
::rres/body data})))
{::yres/status 405
::yres/body data}
{::yres/status 400
::yres/body data})))
(defmethod handle-error :rate-limit
[err _ _]
(let [headers (-> err ex-data ::http/headers)]
{::rres/status 429
::rres/headers headers}))
{::yres/status 429
::yres/headers headers}))
(defmethod handle-error :concurrency-limit
[err _ _]
(let [headers (-> err ex-data ::http/headers)]
{::rres/status 429
::rres/headers headers}))
{::yres/status 429
::yres/headers headers}))
(defmethod handle-error :validation
[err request parent-cause]
@@ -84,22 +84,26 @@
(= code :schema-validation)
(= code :data-validation))
(let [explain (ex/explain data)]
{::rres/status 400
::rres/body (-> data
{::yres/status 400
::yres/body (-> data
(dissoc ::s/problems ::s/value ::s/spec ::sm/explain)
(cond-> explain (assoc :explain explain)))})
(= code :vern-conflict)
{::yres/status 409 ;; 409 - Conflict
::yres/body data}
(= code :request-body-too-large)
{::rres/status 413 ::rres/body data}
{::yres/status 413 ::yres/body data}
(= code :invalid-image)
(binding [l/*context* (request->context request)]
(let [cause (or parent-cause err)]
(l/warn :hint "unexpected error on processing image" :cause cause)
{::rres/status 400 ::rres/body data}))
{::yres/status 400 ::yres/body data}))
:else
{::rres/status 400 ::rres/body data})))
{::yres/status 400 ::yres/body data})))
(defmethod handle-error :assertion
[error request parent-cause]
@@ -110,46 +114,47 @@
(= code :data-validation)
(let [explain (ex/explain data)]
(l/error :hint "data assertion error" :cause cause)
{::rres/status 500
::rres/body {:type :server-error
:code :assertion
:data (-> data
(dissoc ::sm/explain)
(cond-> explain (assoc :explain explain)))}})
{::yres/status 500
::yres/body (-> data
(dissoc ::sm/explain)
(cond-> explain (assoc :explain explain))
(assoc :type :server-error)
(assoc :code :assertion))})
(= code :spec-validation)
(let [explain (ex/explain data)]
(l/error :hint "spec assertion error" :cause cause)
{::rres/status 500
::rres/body {:type :server-error
:code :assertion
:data (-> data
(dissoc ::s/problems ::s/value ::s/spec)
(cond-> explain (assoc :explain explain)))}})
{::yres/status 500
::yres/body (-> data
(dissoc ::s/problems ::s/value ::s/spec)
(cond-> explain (assoc :explain explain))
(assoc :type :server-error)
(assoc :code :assertion))})
:else
(do
(l/error :hint "assertion error" :cause cause)
{::rres/status 500
::rres/body {:type :server-error
:code :assertion
:data data}})))))
{::yres/status 500
::yres/body (-> data
(assoc :type :server-error)
(assoc :code :assertion))})))))
(defmethod handle-error :not-found
[err _ _]
{::rres/status 404
::rres/body (ex-data err)})
{::yres/status 404
::yres/body (ex-data err)})
(defmethod handle-error :internal
[error request parent-cause]
(binding [l/*context* (request->context request)]
(let [cause (or parent-cause error)]
(let [cause (or parent-cause error)
data (ex-data error)]
(l/error :hint "internal error" :cause cause)
{::rres/status 500
::rres/body {:type :server-error
:code :unhandled
:hint (ex-message error)
:data (ex-data error)}})))
{::yres/status 500
::yres/body (-> data
(assoc :type :server-error)
(update :code #(or % :unhandled))
(assoc :hint (ex-message error)))})))
(defmethod handle-error :default
[error request parent-cause]
@@ -173,20 +178,20 @@
:cause cause)
(cond
(= state "57014")
{::rres/status 504
::rres/body {:type :server-error
{::yres/status 504
::yres/body {:type :server-error
:code :statement-timeout
:hint (ex-message error)}}
(= state "25P03")
{::rres/status 504
::rres/body {:type :server-error
{::yres/status 504
::yres/body {:type :server-error
:code :idle-in-transaction-timeout
:hint (ex-message error)}}
:else
{::rres/status 500
::rres/body {:type :server-error
{::yres/status 500
::yres/body {:type :server-error
:code :unexpected
:hint (ex-message error)
:state state}}))))
@@ -200,25 +205,25 @@
(nil? edata)
(binding [l/*context* (request->context request)]
(l/error :hint "unexpected error" :cause cause)
{::rres/status 500
::rres/body {:type :server-error
{::yres/status 500
::yres/body {:type :server-error
:code :unexpected
:hint (ex-message error)}})
:else
(binding [l/*context* (request->context request)]
(l/error :hint "unhandled error" :cause cause)
{::rres/status 500
::rres/body {:type :server-error
:code :unhandled
:hint (ex-message error)
:data edata}}))))
{::yres/status 500
::yres/body (-> edata
(assoc :type :server-error)
(update :code #(or % :unhandled))
(assoc :hint (ex-message error)))}))))
(defmethod handle-exception java.io.IOException
[cause _ _]
(l/wrn :hint "io exception" :cause cause)
{::rres/status 500
::rres/body {:type :server-error
{::yres/status 500
::yres/body {:type :server-error
:code :io-exception
:hint (ex-message cause)}})
@@ -244,4 +249,4 @@
(defn handle'
[cause request]
(::rres/body (handle cause request)))
(::yres/body (handle cause request)))

View File

@@ -7,16 +7,18 @@
(ns app.http.middleware
(:require
[app.common.exceptions :as ex]
[app.common.json :as json]
[app.common.logging :as l]
[app.common.schema :as-alias sm]
[app.common.transit :as t]
[app.config :as cf]
[app.http.errors :as errors]
[clojure.data.json :as json]
[app.util.pointer-map :as pmap]
[cuerdas.core :as str]
[ring.request :as rreq]
[ring.response :as rres]
[yetti.adapter :as yt]
[yetti.middleware :as ymw])
[yetti.middleware :as ymw]
[yetti.request :as yreq]
[yetti.response :as yres])
(:import
io.undertow.server.RequestTooBigException
java.io.InputStream
@@ -35,27 +37,17 @@
(defn- get-reader
^java.io.BufferedReader
[request]
(let [^InputStream body (rreq/body request)]
(let [^InputStream body (yreq/body request)]
(java.io.BufferedReader.
(java.io.InputStreamReader. body))))
(defn- read-json-key
[k]
(-> k str/kebab keyword))
(defn- write-json-key
[k]
(if (or (keyword? k) (symbol? k))
(str/camel k)
(str k)))
(defn wrap-parse-request
[handler]
(letfn [(process-request [request]
(let [header (rreq/get-header request "content-type")]
(let [header (yreq/get-header request "content-type")]
(cond
(str/starts-with? header "application/transit+json")
(with-open [^InputStream is (rreq/body request)]
(with-open [^InputStream is (yreq/body request)]
(let [params (t/read! (t/reader is))]
(-> request
(assoc :body-params params)
@@ -63,7 +55,7 @@
(str/starts-with? header "application/json")
(with-open [reader (get-reader request)]
(let [params (json/read reader :key-fn read-json-key)]
(let [params (json/read reader :key-fn json/read-kebab-key)]
(-> request
(assoc :body-params params)
(update :params merge params))))
@@ -93,7 +85,7 @@
(errors/handle cause request)))]
(fn [request]
(if (= (rreq/method request) :post)
(if (= (yreq/method request) :post)
(try
(-> request process-request handler)
(catch Throwable cause
@@ -113,58 +105,61 @@
(def ^:const buffer-size (:xnio/buffer-size yt/defaults))
(defn- write-json-value
[_ val]
(if (pmap/pointer-map? val)
[(pmap/get-id val) (meta val)]
val))
(defn wrap-format-response
[handler]
(letfn [(transit-streamable-body [data opts]
(reify rres/StreamableResponseBody
(-write-body-to-stream [_ _ output-stream]
(try
(with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)]
(let [tw (t/writer bos opts)]
(t/write! tw data)))
(catch java.io.IOException _)
(catch Throwable cause
(binding [l/*context* {:value data}]
(l/error :hint "unexpected error on encoding response"
:cause cause)))
(finally
(.close ^OutputStream output-stream))))))
(letfn [(transit-streamable-body [data opts _ output-stream]
(try
(with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)]
(let [tw (t/writer bos opts)]
(t/write! tw data)))
(catch java.io.IOException _)
(catch Throwable cause
(binding [l/*context* {:value data}]
(l/error :hint "unexpected error on encoding response"
:cause cause)))
(finally
(.close ^OutputStream output-stream))))
(json-streamable-body [data]
(reify rres/StreamableResponseBody
(-write-body-to-stream [_ _ output-stream]
(try
(with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)]
(with-open [^java.io.OutputStreamWriter writer (java.io.OutputStreamWriter. bos)]
(json/write data writer :key-fn write-json-key)))
(catch java.io.IOException _)
(catch Throwable cause
(binding [l/*context* {:value data}]
(l/error :hint "unexpected error on encoding response"
:cause cause)))
(finally
(.close ^OutputStream output-stream))))))
(json-streamable-body [data _ output-stream]
(try
(let [encode (or (-> data meta :encode/json) identity)
data (encode data)]
(with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)]
(with-open [^java.io.OutputStreamWriter writer (java.io.OutputStreamWriter. bos)]
(json/write writer data :key-fn json/write-camel-key :value-fn write-json-value))))
(catch java.io.IOException _)
(catch Throwable cause
(binding [l/*context* {:value data}]
(l/error :hint "unexpected error on encoding response"
:cause cause)))
(finally
(.close ^OutputStream output-stream))))
(format-response-with-json [response _]
(let [body (::rres/body response)]
(let [body (::yres/body response)]
(if (or (boolean? body) (coll? body))
(-> response
(update ::rres/headers assoc "content-type" "application/json")
(assoc ::rres/body (json-streamable-body body)))
(update ::yres/headers assoc "content-type" "application/json")
(assoc ::yres/body (yres/stream-body (partial json-streamable-body body))))
response)))
(format-response-with-transit [response request]
(let [body (::rres/body response)]
(let [body (::yres/body response)]
(if (or (boolean? body) (coll? body))
(let [qs (rreq/query request)
(let [qs (yreq/query request)
opts (if (or (contains? cf/flags :transit-readable-response)
(str/includes? qs "transit_verbose"))
{:type :json-verbose}
{:type :json})]
(-> response
(update ::rres/headers assoc "content-type" "application/transit+json")
(assoc ::rres/body (transit-streamable-body body opts))))
(update ::yres/headers assoc "content-type" "application/transit+json")
(assoc ::yres/body (yres/stream-body (partial transit-streamable-body body opts)))))
response)))
(format-from-params [{:keys [query-params] :as request}]
@@ -173,7 +168,7 @@
(format-response [response request]
(let [accept (or (format-from-params request)
(rreq/get-header request "accept"))]
(yreq/get-header request "accept"))]
(cond
(or (= accept "application/transit+json")
(str/includes? accept "application/transit+json"))
@@ -222,11 +217,11 @@
(defn wrap-cors
[handler]
(fn [request]
(let [response (if (= (rreq/method request) :options)
{::rres/status 200}
(let [response (if (= (yreq/method request) :options)
{::yres/status 200}
(handler request))
origin (rreq/get-header request "origin")]
(update response ::rres/headers with-cors-headers origin))))
origin (yreq/get-header request "origin")]
(update response ::yres/headers with-cors-headers origin))))
(def cors
{:name ::cors
@@ -241,7 +236,7 @@
(when-let [allowed (:allowed-methods data)]
(fn [handler]
(fn [request]
(let [method (rreq/method request)]
(let [method (yreq/method request)]
(if (contains? allowed method)
(handler request)
{::rres/status 405}))))))})
{::yres/status 405}))))))})

View File

@@ -9,7 +9,7 @@
(:require
[app.common.data :as d]
[app.common.logging :as l]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.common.uri :as u]
[app.config :as cf]
[app.db :as db]
@@ -19,11 +19,9 @@
[app.setup :as-alias setup]
[app.tokens :as tokens]
[app.util.time :as dt]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig]
[ring.request :as rreq]
[yetti.request :as yrq]))
[yetti.request :as yreq]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DEFAULTS
@@ -52,21 +50,32 @@
(update! [_ data])
(delete! [_ key]))
(s/def ::manager #(satisfies? ISessionManager %))
(defn manager?
[o]
(satisfies? ISessionManager o))
(sm/register!
{:type ::manager
:pred manager?})
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STORAGE IMPL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::session-params
(s/keys :req-un [::user-agent
::profile-id
::created-at]))
(def ^:private schema:params
[:map {:title "session-params"}
[:user-agent ::sm/text]
[:profile-id ::sm/uuid]
[:created-at ::sm/inst]])
(def ^:private valid-params?
(sm/validator schema:params))
(defn- prepare-session-params
[key params]
(us/assert! ::us/not-empty-string key)
(us/assert! ::session-params params)
(assert (string? key) "expected key to be a string")
(assert (not (str/blank? key)) "expected key to be not empty")
(assert (valid-params? params) "expected valid params")
{:user-agent (:user-agent params)
:profile-id (:profile-id params)
@@ -117,8 +126,9 @@
(swap! cache dissoc token)
nil))))
(defmethod ig/pre-init-spec ::manager [_]
(s/keys :req [::db/pool]))
(defmethod ig/assert-key ::manager
[_ params]
(assert (db/pool? (::db/pool params)) "expect valid database pool"))
(defmethod ig/init-key ::manager
[_ {:keys [::db/pool]}]
@@ -141,11 +151,11 @@
(defn create-fn
[{:keys [::manager ::setup/props]} profile-id]
(us/assert! ::manager manager)
(us/assert! ::us/uuid profile-id)
(assert (manager? manager) "expected valid session manager")
(assert (uuid? profile-id) "expected valid uuid for profile-id")
(fn [request response]
(let [uagent (rreq/get-header request "user-agent")
(let [uagent (yreq/get-header request "user-agent")
params {:profile-id profile-id
:user-agent uagent
:created-at (dt/now)}
@@ -158,10 +168,10 @@
(defn delete-fn
[{:keys [::manager]}]
(us/assert! ::manager manager)
(assert (manager? manager) "expected valid session manager")
(fn [request response]
(let [cname (cf/get :auth-token-cookie-name default-auth-token-cookie-name)
cookie (yrq/get-cookie request cname)]
cookie (yreq/get-cookie request cname)]
(l/trace :hint "delete" :profile-id (:profile-id request))
(some->> (:value cookie) (delete! manager))
(-> response
@@ -183,7 +193,7 @@
(defn- get-token
[request]
(let [cname (cf/get :auth-token-cookie-name default-auth-token-cookie-name)
cookie (some-> (yrq/get-cookie request cname) :value)]
cookie (some-> (yreq/get-cookie request cname) :value)]
(when-not (str/empty? cookie)
cookie)))
@@ -199,7 +209,7 @@
(defn- wrap-soft-auth
[handler {:keys [::manager ::setup/props]}]
(us/assert! ::manager manager)
(assert (manager? manager) "expected valid session manager")
(letfn [(handle-request [request]
(try
(let [token (get-token request)
@@ -217,7 +227,7 @@
(defn- wrap-authz
[handler {:keys [::manager]}]
(us/assert! ::manager manager)
(assert (manager? manager) "expected valid session manager")
(fn [request]
(let [session (get-session manager (::token request))
request (cond-> request
@@ -308,16 +318,17 @@
;; TASK: SESSION GC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::tasks/max-age ::dt/duration)
;; FIXME: MOVE
(defmethod ig/pre-init-spec ::tasks/gc [_]
(s/keys :req [::db/pool]
:opt [::tasks/max-age]))
(defmethod ig/assert-key ::tasks/gc
[_ params]
(assert (db/pool? (::db/pool params)) "expected valid database pool")
(assert (dt/duration? (::tasks/max-age params))))
(defmethod ig/prep-key ::tasks/gc
[_ cfg]
(defmethod ig/expand-key ::tasks/gc
[k v]
(let [max-age (cf/get :auth-token-cookie-max-age default-cookie-max-age)]
(merge {::tasks/max-age max-age} (d/without-nils cfg))))
{k (merge {::tasks/max-age max-age} (d/without-nils v))}))
(def ^:private
sql:delete-expired

View File

@@ -9,6 +9,7 @@
(:refer-clojure :exclude [tap])
(:require
[app.common.data :as d]
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.transit :as t]
[app.http.errors :as errors]
@@ -16,7 +17,7 @@
[promesa.exec :as px]
[promesa.exec.csp :as sp]
[promesa.util :as pu]
[ring.response :as rres])
[yetti.response :as yres])
(:import
java.io.OutputStream))
@@ -49,21 +50,21 @@
(defn response
[handler & {:keys [buf] :or {buf 32} :as opts}]
(fn [request]
{::rres/headers default-headers
::rres/status 200
::rres/body (reify rres/StreamableResponseBody
(-write-body-to-stream [_ _ output]
(binding [events/*channel* (sp/chan :buf buf :xf (keep encode))]
(let [listener (events/start-listener
(partial write! output)
(partial pu/close! output))]
(try
(let [result (handler)]
(events/tap :end result))
(catch Throwable cause
(l/err :hint "unexpected error on processing sse response"
:cause cause)
(events/tap :error (errors/handle' cause request)))
(finally
(sp/close! events/*channel*)
(px/await! listener)))))))}))
{::yres/headers default-headers
::yres/status 200
::yres/body (yres/stream-body
(fn [_ output]
(binding [events/*channel* (sp/chan :buf buf :xf (keep encode))]
(let [listener (events/start-listener
(partial write! output)
(partial pu/close! output))]
(try
(let [result (handler)]
(events/tap :end result))
(catch Throwable cause
(events/tap :error (errors/handle' cause request))
(when-not (ex/instance? java.io.EOFException cause)
(l/err :hint "unexpected error on processing sse response" :cause cause)))
(finally
(sp/close! events/*channel*)
(px/await! listener)))))))}))

View File

@@ -18,10 +18,8 @@
[app.msgbus :as mbus]
[app.util.time :as dt]
[app.util.websocket :as ws]
[clojure.spec.alpha :as s]
[integrant.core :as ig]
[promesa.exec.csp :as sp]
[ring.websocket :as rws]
[yetti.websocket :as yws]))
(def recv-labels
@@ -113,7 +111,6 @@
fsub (::file-subscription @state)
tsub (::team-subscription @state)
msg {:type :disconnect
:subs-id profile-id
:profile-id profile-id
:session-id session-id}]
@@ -138,9 +135,7 @@
(l/trace :fn "handle-message" :event "subscribe-team" :team-id team-id :conn-id id)
(let [prev-subs (get @state ::team-subscription)
channel (sp/chan :buf (sp/dropping-buffer 64)
:xf (comp
(remove #(= (:session-id %) session-id))
(map #(assoc % :subs-id team-id))))]
:xf (remove #(= (:session-id %) session-id)))]
(sp/pipe channel output-ch false)
(mbus/sub! msgbus :topic team-id :chan channel)
@@ -159,8 +154,7 @@
(l/trace :fn "handle-message" :event "subscribe-file" :file-id file-id :conn-id id)
(let [psub (::file-subscription @state)
fch (sp/chan :buf (sp/dropping-buffer 64)
:xf (comp (remove #(= (:session-id %) session-id))
(map #(assoc % :subs-id file-id))))]
:xf (remove #(= (:session-id %) session-id)))]
(let [subs {:file-id file-id :channel fch :topic file-id}]
(swap! state assoc ::file-subscription subs))
@@ -191,7 +185,6 @@
;; Notifify the rest of participants of the new connection.
(let [message {:type :join-file
:file-id file-id
:subs-id file-id
:session-id session-id
:profile-id profile-id}]
(mbus/pub! msgbus :topic file-id :message message))))
@@ -278,18 +271,18 @@
:inc 1)
message)
(def ^:private schema:params
(sm/define
[:map {:title "params"}
[:session-id ::sm/uuid]]))
(defn- http-handler
[cfg {:keys [params ::session/profile-id] :as request}]
(let [{:keys [session-id]} (sm/conform! schema:params params)]
(let [session-id (some-> params :session-id sm/parse-uuid)]
(when-not (uuid? session-id)
(ex/raise :type :validation
:code :missing-session-id
:hint "missing or invalid session-id found"))
(cond
(not profile-id)
(ex/raise :type :authentication
:hint "Authentication required.")
:hint "authentication required")
;; WORKAROUND: we use the adapter specific predicate for
;; performance reasons; for now, the ring default impl for
@@ -303,7 +296,7 @@
:else
(do
(l/trace :hint "websocket request" :profile-id profile-id :session-id session-id)
{::rws/listener (ws/listener request
{::yws/listener (ws/listener request
::ws/on-rcv-message (partial on-rcv-message cfg)
::ws/on-snd-message (partial on-snd-message cfg)
::ws/on-connect (partial on-connect cfg)
@@ -311,13 +304,17 @@
::profile-id profile-id
::session-id session-id)}))))
(defmethod ig/pre-init-spec ::routes [_]
(s/keys :req [::mbus/msgbus
::mtx/metrics
::db/pool
::session/manager]))
(s/def ::routes vector?)
(def ^:private schema:routes-params
[:map
::mbus/msgbus
::mtx/metrics
::db/pool
::session/manager])
(defmethod ig/assert-key ::routes
[_ params]
(assert (sm/valid? schema:routes-params params)))
(defmethod ig/init-key ::routes
[_ cfg]

View File

@@ -10,7 +10,7 @@
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.logging :as l]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.common.uuid :as uuid]
[app.config :as cf]
[app.db :as db]
@@ -25,9 +25,7 @@
[app.util.services :as-alias sv]
[app.util.time :as dt]
[app.worker :as wrk]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig]))
[cuerdas.core :as str]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; HELPERS
@@ -95,46 +93,28 @@
;; --- SPECS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COLLECTOR
;; COLLECTOR API
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Defines a service that collects the audit/activity log using
;; internal database. Later this audit log can be transferred to
;; an external storage and data cleared.
(s/def ::profile-id ::us/uuid)
(s/def ::name ::us/string)
(s/def ::type ::us/string)
(s/def ::props (s/map-of ::us/keyword any?))
(s/def ::ip-addr ::us/string)
(def ^:private schema:event
[:map {:title "event"}
[::type ::sm/text]
[::name ::sm/text]
[::profile-id ::sm/uuid]
[::ip-addr {:optional true} ::sm/text]
[::props {:optional true} [:map-of :keyword :any]]
[::context {:optional true} [:map-of :keyword :any]]
[::webhooks/event? {:optional true} ::sm/boolean]
[::webhooks/batch-timeout {:optional true} ::dt/duration]
[::webhooks/batch-key {:optional true}
[:or ::sm/fn ::sm/text :keyword]]])
(s/def ::webhooks/event? ::us/boolean)
(s/def ::webhooks/batch-timeout ::dt/duration)
(s/def ::webhooks/batch-key
(s/or :fn fn? :str string? :kw keyword?))
(s/def ::event
(s/keys :req [::type ::name ::profile-id]
:opt [::ip-addr
::props
::webhooks/event?
::webhooks/batch-timeout
::webhooks/batch-key]))
(s/def ::collector
(s/keys :req [::wrk/executor ::db/pool]))
(defmethod ig/pre-init-spec ::collector [_]
(s/keys :req [::db/pool ::wrk/executor]))
(defmethod ig/init-key ::collector
[_ {:keys [::db/pool] :as cfg}]
(cond
(db/read-only? pool)
(l/warn :hint "audit disabled (db is read-only)")
:else
cfg))
(def ^:private check-event
(sm/check-fn schema:event))
(defn prepare-event
[cfg mdata params result]
@@ -263,6 +243,8 @@
(assoc ::wrk/dedupe dedupe?)
(assoc ::wrk/label label)
(assoc ::wrk/params (-> params
(dissoc :source)
(dissoc :context)
(dissoc :ip-addr)
(dissoc :type)))))))
params))
@@ -271,12 +253,12 @@
"Submit audit event to the collector."
[cfg event]
(try
(let [event (d/without-nils event)
(let [event (-> (d/without-nils event)
(check-event))
cfg (-> cfg
(assoc ::rtry/when rtry/conflict-exception?)
(assoc ::rtry/max-retries 6)
(assoc ::rtry/label "persist-audit-log"))]
(us/verify! ::event event)
(rtry/invoke! cfg db/tx-run! handle-event! event))
(catch Throwable cause
(l/error :hint "unexpected error processing event" :cause cause))))
@@ -287,8 +269,8 @@
logic."
[cfg event]
(when (contains? cf/flags :audit-log)
(let [event (d/without-nils event)]
(us/verify! ::event event)
(let [event (-> (d/without-nils event)
(check-event))]
(db/run! cfg (fn [cfg]
(let [tnow (dt/now)
params (-> (event->params event)

View File

@@ -8,6 +8,7 @@
(:require
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.schema :as sm]
[app.common.transit :as t]
[app.common.uuid :as uuid]
[app.config :as cf]
@@ -16,7 +17,6 @@
[app.setup :as-alias setup]
[app.tokens :as tokens]
[app.util.time :as dt]
[clojure.spec.alpha :as s]
[integrant.core :as ig]
[lambdaisland.uri :as u]
[promesa.exec :as px]))
@@ -108,8 +108,15 @@
(mark-archived! cfg rows)
(count events)))))))
(defmethod ig/pre-init-spec ::handler [_]
(s/keys :req [::db/pool ::setup/props ::http/client]))
(def ^:private schema:handler-params
[:map
::db/pool
::setup/props
::http/client])
(defmethod ig/assert-key ::handler
[_ params]
(assert (sm/valid? schema:handler-params params) "valid params expected for handler"))
(defmethod ig/init-key ::handler
[_ cfg]

View File

@@ -8,7 +8,6 @@
(:require
[app.common.logging :as l]
[app.db :as db]
[clojure.spec.alpha :as s]
[integrant.core :as ig]))
(def ^:private sql:clean-archived
@@ -22,8 +21,9 @@
(l/debug :hint "delete archived audit log entries" :deleted result)
result))
(defmethod ig/pre-init-spec ::handler [_]
(s/keys :req [::db/pool]))
(defmethod ig/assert-key ::handler
[_ params]
(assert (db/pool? (::db/pool params)) "valid database pool expected"))
(defmethod ig/init-key ::handler
[_ cfg]

View File

@@ -12,7 +12,6 @@
[app.common.logging :as l]
[app.common.pprint :as pp]
[app.common.schema :as sm]
[app.common.spec :as us]
[app.config :as cf]
[app.db :as db]
[clojure.spec.alpha :as s]
@@ -38,7 +37,7 @@
(defn record->report
[{:keys [::l/context ::l/message ::l/props ::l/logger ::l/level ::l/cause] :as record}]
(us/assert! ::l/record record)
(assert (l/valid-record? record) "expectd valid log record")
(if (or (instance? java.util.concurrent.CompletionException cause)
(instance? java.util.concurrent.ExecutionException cause))
(-> record
@@ -63,7 +62,7 @@
(ex/format-throwable cause :data? false :explain? false :header? false :summary? false))}
(when-let [params (or (:request/params context) (:params context))]
{:params (pp/pprint-str params :length 30 :level 12)})
{:params (pp/pprint-str params :length 30 :level 13)})
(when-let [value (:value context)]
{:value (pp/pprint-str value :length 30 :level 12)})
@@ -91,8 +90,9 @@
(catch Throwable cause
(l/warn :hint "unexpected exception on database error logger" :cause cause))))
(defmethod ig/pre-init-spec ::reporter [_]
(s/keys :req [::db/pool]))
(defmethod ig/assert-key ::reporter
[_ params]
(assert (db/pool? (::db/pool params)) "expect valid database pool"))
(defmethod ig/init-key ::reporter
[_ cfg]

View File

@@ -9,12 +9,10 @@
(:require
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.spec :as us]
[app.config :as cf]
[app.http.client :as http]
[app.loggers.database :as ldb]
[app.util.json :as json]
[clojure.spec.alpha :as s]
[integrant.core :as ig]
[promesa.exec :as px]
[promesa.exec.csp :as sp]))
@@ -54,7 +52,7 @@
(defn record->report
[{:keys [::l/context ::l/id ::l/cause] :as record}]
(us/assert! ::l/record record)
(assert (l/valid-record? record) "expectd valid log record")
{:id id
:tenant (cf/get :tenant)
:host (cf/get :host)
@@ -75,8 +73,9 @@
(catch Throwable cause
(l/warn :hint "unhandled error" :cause cause)))))
(defmethod ig/pre-init-spec ::reporter [_]
(s/keys :req [::http/client]))
(defmethod ig/assert-key ::reporter
[_ params]
(assert (http/client? (::http/client params)) "expect valid http client"))
(defmethod ig/init-key ::reporter
[_ cfg]

View File

@@ -18,7 +18,6 @@
[app.util.time :as dt]
[app.worker :as wrk]
[clojure.data.json :as json]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig]))
@@ -60,27 +59,26 @@
(some->> (:project-id props) (lookup-webhooks-by-project pool))
(some->> (:file-id props) (lookup-webhooks-by-file pool))))
(defmethod ig/pre-init-spec ::process-event-handler [_]
(s/keys :req [::db/pool]))
(defmethod ig/assert-key ::process-event-handler
[_ params]
(assert (db/pool? (::db/pool params)) "expect valid database pool")
(assert (http/client? (::http/client params)) "expect valid http client"))
(defmethod ig/init-key ::process-event-handler
[_ cfg]
(fn [{:keys [props] :as task}]
(let [event (:event props)]
(l/dbg :hint "process webhook event" :name (:name event))
(when-let [items (lookup-webhooks cfg event)]
(l/trc :hint "webhooks found for event" :total (count items))
(db/tx-run! cfg (fn [cfg]
(doseq [item items]
(wrk/submit! (-> cfg
(assoc ::wrk/task :run-webhook)
(assoc ::wrk/queue :webhooks)
(assoc ::wrk/max-retries 3)
(assoc ::wrk/params {:event event
:config item}))))))))))
(l/dbg :hint "process webhook event" :name (:name props))
(when-let [items (lookup-webhooks cfg props)]
(l/trc :hint "webhooks found for event" :total (count items))
(db/tx-run! cfg (fn [cfg]
(doseq [item items]
(wrk/submit! (-> cfg
(assoc ::wrk/task :run-webhook)
(assoc ::wrk/queue :webhooks)
(assoc ::wrk/max-retries 3)
(assoc ::wrk/params {:event props
:config item})))))))))
;; --- RUN
(declare interpret-exception)
@@ -90,12 +88,14 @@
{:key-fn str/camel
:indent true})
(defmethod ig/pre-init-spec ::run-webhook-handler [_]
(s/keys :req [::http/client ::db/pool]))
(defmethod ig/assert-key ::run-webhook-handler
[_ params]
(assert (db/pool? (::db/pool params)) "expect valid database pool")
(assert (http/client? (::http/client params)) "expect valid http client"))
(defmethod ig/prep-key ::run-webhook-handler
[_ cfg]
(merge {::max-errors 3} (d/without-nils cfg)))
(defmethod ig/expand-key ::run-webhook-handler
[k v]
{k (merge {::max-errors 3} (d/without-nils v))})
(defmethod ig/init-key ::run-webhook-handler
[_ {:keys [::db/pool ::max-errors] :as cfg}]
@@ -138,7 +138,7 @@
(l/dbg :hint "run webhook"
:event-name (:name event)
:webhook-id (:id whook)
:webhook-id (str (:id whook))
:webhook-uri (:uri whook)
:webhook-mtype (:mtype whook))

View File

@@ -9,6 +9,7 @@
[app.auth.ldap :as-alias ldap]
[app.auth.oidc :as-alias oidc]
[app.auth.oidc.providers :as-alias oidc.providers]
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.config :as cf]
[app.db :as-alias db]
@@ -28,6 +29,7 @@
[app.msgbus :as-alias mbus]
[app.redis :as-alias rds]
[app.rpc :as-alias rpc]
[app.rpc.climit :as-alias climit]
[app.rpc.doc :as-alias rpc.doc]
[app.setup :as-alias setup]
[app.srepl :as-alias srepl]
@@ -169,7 +171,7 @@
{::db/uri (cf/get :database-uri)
::db/username (cf/get :database-username)
::db/password (cf/get :database-password)
::db/read-only? (cf/get :database-readonly false)
::db/read-only (cf/get :database-readonly false)
::db/min-size (cf/get :database-min-pool-size 0)
::db/max-size (cf/get :database-max-pool-size 60)
::mtx/metrics (ig/ref ::mtx/metrics)}
@@ -245,7 +247,7 @@
:base-dn (cf/get :ldap-base-dn)
:bind-dn (cf/get :ldap-bind-dn)
:bind-password (cf/get :ldap-bind-password)
:enabled? (contains? cf/flags :login-with-ldap)}
:enabled (contains? cf/flags :login-with-ldap)}
::oidc.providers/google
{}
@@ -302,9 +304,11 @@
::http.assets/cache-max-agesignature-max-age (dt/duration {:hours 24 :minutes 5})
::sto/storage (ig/ref ::sto/storage)}
:app.rpc/climit
{::mtx/metrics (ig/ref ::mtx/metrics)
::wrk/executor (ig/ref ::wrk/executor)}
::rpc/climit
{::mtx/metrics (ig/ref ::mtx/metrics)
::wrk/executor (ig/ref ::wrk/executor)
::climit/config (cf/get :rpc-climit-config)
::climit/enabled (contains? cf/flags :rpc-climit)}
:app.rpc/rlimit
{::wrk/executor (ig/ref ::wrk/executor)}
@@ -319,7 +323,6 @@
::mtx/metrics (ig/ref ::mtx/metrics)
::mbus/msgbus (ig/ref ::mbus/msgbus)
::rds/redis (ig/ref ::rds/redis)
::svgo/optimizer (ig/ref ::svgo/optimizer)
::rpc/climit (ig/ref ::rpc/climit)
::rpc/rlimit (ig/ref ::rpc/rlimit)
@@ -330,7 +333,7 @@
::email/whitelist (ig/ref ::email/whitelist)}
:app.rpc.doc/routes
{:methods (ig/ref :app.rpc/methods)}
{:app.rpc/methods (ig/ref :app.rpc/methods)}
:app.rpc/routes
{::rpc/methods (ig/ref :app.rpc/methods)
@@ -344,6 +347,8 @@
{:sendmail (ig/ref ::email/handler)
:objects-gc (ig/ref :app.tasks.objects-gc/handler)
:file-gc (ig/ref :app.tasks.file-gc/handler)
:file-gc-scheduler (ig/ref :app.tasks.file-gc-scheduler/handler)
:offload-file-data (ig/ref :app.tasks.offload-file-data/handler)
:file-xlog-gc (ig/ref :app.tasks.file-xlog-gc/handler)
:tasks-gc (ig/ref :app.tasks.tasks-gc/handler)
:telemetry (ig/ref :app.tasks.telemetry/handler)
@@ -377,8 +382,7 @@
::email/default-from (cf/get :smtp-default-from)}
::email/handler
{::email/sendmail (ig/ref ::email/sendmail)
::mtx/metrics (ig/ref ::mtx/metrics)}
{::email/sendmail (ig/ref ::email/sendmail)}
:app.tasks.tasks-gc/handler
{::db/pool (ig/ref ::db/pool)}
@@ -394,9 +398,17 @@
{::db/pool (ig/ref ::db/pool)
::sto/storage (ig/ref ::sto/storage)}
:app.tasks.file-xlog-gc/handler
:app.tasks.file-gc-scheduler/handler
{::db/pool (ig/ref ::db/pool)}
:app.tasks.offload-file-data/handler
{::db/pool (ig/ref ::db/pool)
::sto/storage (ig/ref ::sto/storage)}
:app.tasks.file-xlog-gc/handler
{::db/pool (ig/ref ::db/pool)
::sto/storage (ig/ref ::sto/storage)}
:app.tasks.telemetry/handler
{::db/pool (ig/ref ::db/pool)
::http.client/client (ig/ref ::http.client/client)
@@ -420,9 +432,6 @@
;; module requires the migrations to run before initialize.
::migrations (ig/ref :app.migrations/migrations)}
::svgo/optimizer
{}
:app.loggers.audit.archive-task/handler
{::setup/props (ig/ref ::setup/props)
::db/pool (ig/ref ::db/pool)
@@ -448,17 +457,29 @@
::sto/storage
{::db/pool (ig/ref ::db/pool)
::sto/backends
{:assets-s3 (ig/ref [::assets :app.storage.s3/backend])
:assets-fs (ig/ref [::assets :app.storage.fs/backend])}}
{:s3 (ig/ref :app.storage.s3/backend)
:fs (ig/ref :app.storage.fs/backend)
[::assets :app.storage.s3/backend]
{::sto.s3/region (cf/get :storage-assets-s3-region)
::sto.s3/endpoint (cf/get :storage-assets-s3-endpoint)
::sto.s3/bucket (cf/get :storage-assets-s3-bucket)
::sto.s3/io-threads (cf/get :storage-assets-s3-io-threads)}
;; LEGACY (should not be removed, can only be removed after an
;; explicit migration because the database objects/rows will
;; still reference the old names).
:assets-s3 (ig/ref :app.storage.s3/backend)
:assets-fs (ig/ref :app.storage.fs/backend)}}
[::assets :app.storage.fs/backend]
{::sto.fs/directory (cf/get :storage-assets-fs-directory)}})
:app.storage.s3/backend
{::sto.s3/region (or (cf/get :storage-assets-s3-region)
(cf/get :objects-storage-s3-region))
::sto.s3/endpoint (or (cf/get :storage-assets-s3-endpoint)
(cf/get :objects-storage-s3-endpoint))
::sto.s3/bucket (or (cf/get :storage-assets-s3-bucket)
(cf/get :objects-storage-s3-bucket))
::sto.s3/io-threads (or (cf/get :storage-assets-s3-io-threads)
(cf/get :objects-storage-s3-io-threads))
::wrk/executor (ig/ref ::wrk/executor)}
:app.storage.fs/backend
{::sto.fs/directory (or (cf/get :storage-assets-fs-directory)
(cf/get :objects-storage-fs-directory))}})
(def worker-config
@@ -466,10 +487,7 @@
{::wrk/registry (ig/ref ::wrk/registry)
::db/pool (ig/ref ::db/pool)
::wrk/entries
[{:cron #app/cron "0 0 * * * ?" ;; hourly
:task :file-xlog-gc}
{:cron #app/cron "0 0 0 * * ?" ;; daily
[{:cron #app/cron "0 0 0 * * ?" ;; daily
:task :session-gc}
{:cron #app/cron "0 0 0 * * ?" ;; daily
@@ -485,7 +503,7 @@
:task :tasks-gc}
{:cron #app/cron "0 0 2 * * ?" ;; daily
:task :file-gc}
:task :file-gc-scheduler}
{:cron #app/cron "0 30 */3,23 * * ?"
:task :telemetry}
@@ -501,11 +519,13 @@
::wrk/dispatcher
{::rds/redis (ig/ref ::rds/redis)
::mtx/metrics (ig/ref ::mtx/metrics)
::db/pool (ig/ref ::db/pool)}
::db/pool (ig/ref ::db/pool)
::wrk/tenant (cf/get :tenant)}
[::default ::wrk/runner]
{::wrk/parallelism (cf/get ::worker-default-parallelism 1)
::wrk/queue :default
::wrk/tenant (cf/get :tenant)
::rds/redis (ig/ref ::rds/redis)
::wrk/registry (ig/ref ::wrk/registry)
::mtx/metrics (ig/ref ::mtx/metrics)
@@ -514,6 +534,7 @@
[::webhook ::wrk/runner]
{::wrk/parallelism (cf/get ::worker-webhook-parallelism 1)
::wrk/queue :webhooks
::wrk/tenant (cf/get :tenant)
::rds/redis (ig/ref ::rds/redis)
::wrk/registry (ig/ref ::wrk/registry)
::mtx/metrics (ig/ref ::mtx/metrics)
@@ -524,13 +545,14 @@
(defn start
[]
(cf/validate!)
(ig/load-namespaces (merge system-config worker-config))
(alter-var-root #'system (fn [sys]
(when sys (ig/halt! sys))
(-> system-config
(cond-> (contains? cf/flags :backend-worker)
(merge worker-config))
(ig/prep)
(ig/expand)
(ig/init))))
(l/inf :hint "welcome to penpot"
:flags (str/join "," (map name cf/flags))
@@ -543,7 +565,7 @@
(alter-var-root #'system (fn [sys]
(when sys (ig/halt! sys))
(-> config
(ig/prep)
(ig/expand)
(ig/init)))))
(defn stop
@@ -599,12 +621,6 @@
(deref p))
(catch Throwable cause
(binding [*out* *err*]
(println "==== ERROR ===="))
(.printStackTrace cause)
(when-let [cause' (ex-cause cause)]
(binding [*out* *err*]
(println "==== CAUSE ===="))
(.printStackTrace cause'))
(ex/print-throwable cause)
(px/sleep 500)
(System/exit -1))))

View File

@@ -11,7 +11,6 @@
[app.common.exceptions :as ex]
[app.common.media :as cm]
[app.common.schema :as sm]
[app.common.schema.generators :as sg]
[app.common.schema.openapi :as-alias oapi]
[app.common.spec :as us]
[app.common.svg :as csvg]
@@ -47,26 +46,15 @@
(s/keys :req-un [::path]
:opt-un [::mtype]))
(sm/def! ::fs/path
{:type ::fs/path
:pred fs/path?
:type-properties
{:title "path"
:description "filesystem path"
:error/message "expected a valid fs path instance"
:gen/gen (sg/generator :string)
::oapi/type "string"
::oapi/format "unix-path"
::oapi/decode fs/path}})
(sm/def! ::upload
[:map {:title "Upload"}
[:filename :string]
[:size :int]
[:path ::fs/path]
[:mtype {:optional true} :string]
[:headers {:optional true}
[:map-of :string :string]]])
(sm/register!
^{::sm/type ::upload}
[:map {:title "Upload"}
[:filename :string]
[:size ::sm/int]
[:path ::fs/path]
[:mtype {:optional true} :string]
[:headers {:optional true}
[:map-of :string :string]]])
(defn validate-media-type!
([upload] (validate-media-type! upload cm/valid-image-types))
@@ -238,7 +226,7 @@
(letfn [(ttf->otf [data]
(let [finput (tmp/tempfile :prefix "penpot.font." :suffix "")
foutput (fs/path (str finput ".otf"))
_ (io/write-to-file! data finput)
_ (io/write* finput data)
res (sh/sh "fontforge" "-lang=ff" "-c"
(str/fmt "Open('%s'); Generate('%s')"
(str finput)
@@ -249,7 +237,7 @@
(otf->ttf [data]
(let [finput (tmp/tempfile :prefix "penpot.font." :suffix "")
foutput (fs/path (str finput ".ttf"))
_ (io/write-to-file! data finput)
_ (io/write* finput data)
res (sh/sh "fontforge" "-lang=ff" "-c"
(str/fmt "Open('%s'); Generate('%s')"
(str finput)
@@ -263,14 +251,14 @@
;; command.
(let [finput (tmp/tempfile :prefix "penpot.font." :suffix "")
foutput (fs/path (str finput ".woff"))
_ (io/write-to-file! data finput)
_ (io/write* finput data)
res (sh/sh "sfnt2woff" (str finput))]
(when (zero? (:exit res))
foutput)))
(woff->sfnt [data]
(let [finput (tmp/tempfile :prefix "penpot" :suffix "")
_ (io/write-to-file! data finput)
_ (io/write* finput data)
res (sh/sh "woff2sfnt" (str finput)
:out-enc :bytes)]
(when (zero? (:exit res))
@@ -326,17 +314,3 @@
(= stype :ttf)
(-> (assoc "font/otf" (ttf->otf sfnt))
(assoc "font/ttf" sfnt)))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Utility functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn configure-assets-storage
"Given storage map, returns a storage configured with the appropriate
backend for assets and optional connection attached."
([storage]
(assoc storage ::sto/backend (cf/get :assets-storage-backend :assets-fs)))
([storage pool-or-conn]
(-> (configure-assets-storage storage)
(assoc ::db/pool-or-conn pool-or-conn))))

View File

@@ -8,9 +8,8 @@
(:refer-clojure :exclude [run!])
(:require
[app.common.logging :as l]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.metrics.definition :as-alias mdef]
[clojure.spec.alpha :as s]
[integrant.core :as ig])
(:import
io.prometheus.client.CollectorRegistry
@@ -34,41 +33,52 @@
(declare create-collector)
(declare handler)
(defprotocol IMetrics
(get-registry [_])
(get-collector [_ id])
(get-handler [_]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; METRICS SERVICE PROVIDER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::mdef/name string?)
(s/def ::mdef/help string?)
(s/def ::mdef/labels (s/every string? :kind vector?))
(s/def ::mdef/type #{:gauge :counter :summary :histogram})
(sm/register!
{:type ::collector
:pred #(instance? SimpleCollector %)
:type-properties
{:title "collector"
:description "An instance of SimpleCollector"}})
(s/def ::mdef/instance
#(instance? SimpleCollector %))
(sm/register!
{:type ::registry
:pred #(instance? CollectorRegistry %)
:type-properties
{:title "Metrics Registry"
:description "Instance of CollectorRegistry"}})
(s/def ::mdef/definition
(s/keys :req [::mdef/name
::mdef/help
::mdef/type]
:opt [::mdef/labels
::mdef/instance]))
(def ^:private schema:definitions
[:map-of :keyword
[:map {:title "definition"}
[::mdef/name :string]
[::mdef/help :string]
[::mdef/type [:enum :gauge :counter :summary :histogram]]
[::mdef/labels {:optional true} [::sm/vec :string]]
[::mdef/instance {:optional true} ::collector]]])
(s/def ::definitions
(s/map-of keyword? ::mdef/definition))
(defn metrics?
[o]
(satisfies? IMetrics o))
(s/def ::registry
#(instance? CollectorRegistry %))
(sm/register!
{:type ::metrics
:pred metrics?})
(s/def ::handler fn?)
(s/def ::metrics
(s/keys :req [::registry
::handler
::definitions]))
(def ^:private valid-definitions?
(sm/validator schema:definitions))
(s/def ::default ::definitions)
(defmethod ig/pre-init-spec ::metrics [_]
(s/keys :req-un [::default]))
(defmethod ig/assert-key ::metrics
[_ {:keys [default]}]
(assert (valid-definitions? default) "expected valid definitions"))
(defmethod ig/init-key ::metrics
[_ cfg]
@@ -81,12 +91,14 @@
{}
(:default cfg))]
(us/verify! ::definitions definitions)
{::handler (partial handler registry)
::definitions definitions
::registry registry}))
(reify
IMetrics
(get-handler [_]
(partial handler registry))
(get-collector [_ id]
(get definitions id))
(get-registry [_]
registry))))
(defn- handler
[registry _]
@@ -96,17 +108,14 @@
{:headers {"content-type" TextFormat/CONTENT_TYPE_004}
:body (.toString writer)}))
(s/def ::routes vector?)
(defmethod ig/pre-init-spec ::routes [_]
(s/keys :req [::metrics]))
(defmethod ig/assert-key ::routes
[_ {:keys [::metrics]}]
(assert (metrics? metrics) "expected a valid instance for metrics"))
(defmethod ig/init-key ::routes
[_ {:keys [::metrics]}]
(let [registry (::registry metrics)]
["/metrics" {:handler (partial handler registry)
:allowed-methods #{:get}}]))
["/metrics" {:handler (get-handler metrics)
:allowed-methods #{:get}}])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Implementation
@@ -126,8 +135,9 @@
(defmulti create-collector ::mdef/type)
(defn run!
[{:keys [::definitions]} & {:keys [id] :as params}]
(when-let [mobj (get definitions id)]
[instance & {:keys [id] :as params}]
(assert (metrics? instance) "expected valid metrics instance")
(when-let [mobj (get-collector instance id)]
(run-collector! mobj params)
true))

View File

@@ -11,7 +11,6 @@
[app.db :as db]
[app.migrations.clj.migration-0023 :as mg0023]
[app.util.migrations :as mg]
[clojure.spec.alpha :as s]
[integrant.core :as ig]))
(def migrations
@@ -379,7 +378,55 @@
:fn (mg/resource "app/migrations/sql/0119-mod-file-table.sql")}
{:name "0120-mod-audit-log-table"
:fn (mg/resource "app/migrations/sql/0120-mod-audit-log-table.sql")}])
:fn (mg/resource "app/migrations/sql/0120-mod-audit-log-table.sql")}
{:name "0121-mod-file-data-fragment-table"
:fn (mg/resource "app/migrations/sql/0121-mod-file-data-fragment-table.sql")}
{:name "0122-mod-file-table"
:fn (mg/resource "app/migrations/sql/0122-mod-file-table.sql")}
{:name "0122-mod-file-data-fragment-table"
:fn (mg/resource "app/migrations/sql/0122-mod-file-data-fragment-table.sql")}
{:name "0123-mod-file-change-table"
:fn (mg/resource "app/migrations/sql/0123-mod-file-change-table.sql")}
{:name "0124-mod-profile-table"
:fn (mg/resource "app/migrations/sql/0124-mod-profile-table.sql")}
{:name "0125-mod-file-table"
:fn (mg/resource "app/migrations/sql/0125-mod-file-table.sql")}
{:name "0126-add-team-access-request-table"
:fn (mg/resource "app/migrations/sql/0126-add-team-access-request-table.sql")}
{:name "0127-mod-storage-object-table"
:fn (mg/resource "app/migrations/sql/0127-mod-storage-object-table.sql")}
{:name "0128-mod-task-table"
:fn (mg/resource "app/migrations/sql/0128-mod-task-table.sql")}
{:name "0129-mod-file-change-table"
:fn (mg/resource "app/migrations/sql/0129-mod-file-change-table.sql")}
{:name "0130-mod-file-change-table"
:fn (mg/resource "app/migrations/sql/0130-mod-file-change-table.sql")}
{:name "0131-mod-webhook-table"
:fn (mg/resource "app/migrations/sql/0131-mod-webhook-table.sql")}
{:name "0132-mod-file-change-table"
:fn (mg/resource "app/migrations/sql/0132-mod-file-change-table.sql")}
{:name "0133-mod-file-table"
:fn (mg/resource "app/migrations/sql/0133-mod-file-table.sql")}
{:name "0134-mod-file-change-table"
:fn (mg/resource "app/migrations/sql/0134-mod-file-change-table.sql")}
{:name "0135-mod-team-invitation-table.sql"
:fn (mg/resource "app/migrations/sql/0135-mod-team-invitation-table.sql")}])
(defn apply-migrations!
[pool name migrations]
@@ -387,9 +434,9 @@
(mg/setup! conn)
(mg/migrate! conn {:name name :steps migrations})))
(defmethod ig/pre-init-spec ::migrations
[_]
(s/keys :req [::db/pool]))
(defmethod ig/assert-key ::migrations
[_ {:keys [::db/pool]}]
(assert (db/pool? pool) "expected valid pool"))
(defmethod ig/init-key ::migrations
[module {:keys [::db/pool]}]

View File

@@ -0,0 +1,8 @@
ALTER TABLE file_data_fragment
ADD COLUMN data bytea NULL;
UPDATE file_data_fragment
SET data = content;
ALTER TABLE file_data_fragment
DROP COLUMN content;

View File

@@ -0,0 +1,6 @@
ALTER TABLE file_data_fragment
ADD COLUMN data_backend text NULL,
ADD COLUMN data_ref_id uuid NULL;
CREATE INDEX IF NOT EXISTS file_data_fragment__data_ref_id__idx
ON file_data_fragment (data_ref_id);

View File

@@ -0,0 +1,6 @@
ALTER TABLE file_data_fragment
ADD COLUMN data_backend text NULL,
ADD COLUMN data_ref_id uuid NULL;
CREATE INDEX IF NOT EXISTS file_data_fragment__data_ref_id__idx
ON file_data_fragment (data_ref_id);

View File

@@ -0,0 +1,4 @@
ALTER TABLE file ADD COLUMN data_ref_id uuid NULL;
CREATE INDEX IF NOT EXISTS file__data_ref_id__idx
ON file (data_ref_id);

View File

@@ -0,0 +1,2 @@
CREATE INDEX IF NOT EXISTS file_change__created_at__label__idx
ON file_change (created_at, label);

View File

@@ -0,0 +1,2 @@
CREATE INDEX profile__props__newsletter1__idx ON profile (email) WHERE props->>'~:newsletter-news' = 'true';
CREATE INDEX profile__props__newsletter2__idx ON profile (email) WHERE props->>'~:newsletter-updates' = 'true';

View File

@@ -0,0 +1,3 @@
--- This setting allow to optimize the table for heavy write workload
--- leaving space on the page for HOT updates
ALTER TABLE file SET (FILLFACTOR=50);

View File

@@ -0,0 +1,10 @@
CREATE TABLE team_access_request (
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
team_id uuid NOT NULL REFERENCES team(id) ON DELETE CASCADE DEFERRABLE,
requester_id uuid NULL REFERENCES profile(id) ON DELETE CASCADE DEFERRABLE,
valid_until timestamptz NOT NULL,
auto_join_until timestamptz NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (team_id, requester_id)
);

View File

@@ -0,0 +1,3 @@
--- This setting allow to optimize the table for heavy write workload
--- leaving space on the page for HOT updates
ALTER TABLE storage_object SET (FILLFACTOR=60);

View File

@@ -0,0 +1,3 @@
--- This setting allow to optimize the table for heavy write workload
--- leaving space on the page for HOT updates
ALTER TABLE task SET (FILLFACTOR=60);

View File

@@ -0,0 +1,6 @@
ALTER TABLE file_change
ADD COLUMN data_backend text NULL,
ADD COLUMN data_ref_id uuid NULL;
CREATE INDEX IF NOT EXISTS file_change__data_ref_id__idx
ON file_change (data_ref_id);

View File

@@ -0,0 +1,2 @@
ALTER TABLE file_change
ADD COLUMN version integer NULL;

View File

@@ -0,0 +1,6 @@
ALTER TABLE webhook
ADD COLUMN profile_id uuid NULL REFERENCES profile (id) ON DELETE SET NULL;
CREATE INDEX webhook__profile_id__idx
ON webhook (profile_id)
WHERE profile_id IS NOT NULL;

View File

@@ -0,0 +1,2 @@
ALTER TABLE file_change
ADD COLUMN created_by text NOT NULL DEFAULT 'system';

View File

@@ -0,0 +1,2 @@
ALTER TABLE file
ADD COLUMN vern int NOT NULL DEFAULT 0;

View File

@@ -0,0 +1,18 @@
ALTER TABLE file_change
ADD COLUMN updated_at timestamptz DEFAULT now(),
ADD COLUMN deleted_at timestamptz DEFAULT NULL,
ALTER COLUMN created_at SET DEFAULT now();
DROP INDEX file_change__created_at__idx;
DROP INDEX file_change__created_at__label__idx;
DROP INDEX file_change__label__idx;
CREATE INDEX file_change__deleted_at__idx
ON file_change (deleted_at, id)
WHERE deleted_at IS NOT NULL;
CREATE INDEX file_change__system_snapshots__idx
ON file_change (file_id, created_at)
WHERE data IS NOT NULL
AND created_by = 'system'
AND deleted_at IS NULL;

View File

@@ -0,0 +1,2 @@
ALTER TABLE team_invitation
ADD COLUMN created_by uuid NULL REFERENCES profile(id) ON DELETE SET NULL;

View File

@@ -9,22 +9,27 @@
(:require
[app.common.data :as d]
[app.common.logging :as l]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.common.transit :as t]
[app.config :as cfg]
[app.redis :as rds]
[app.util.time :as dt]
[app.worker :as wrk]
[clojure.spec.alpha :as s]
[integrant.core :as ig]
[promesa.core :as p]
[promesa.exec :as px]
[promesa.exec.csp :as sp]))
(set! *warn-on-reflection* true)
(def ^:private prefix (cfg/get :tenant))
(defprotocol IMsgBus
(-sub [_ topics chan])
(-pub [_ topic message])
(-purge [_ chans]))
(defn- prefix-topic
[topic]
(str prefix "." topic))
@@ -32,30 +37,33 @@
(def ^:private xform-prefix-topic
(map (fn [obj] (update obj :topic prefix-topic))))
(declare ^:private redis-pub!)
(declare ^:private redis-sub!)
(declare ^:private redis-unsub!)
(declare ^:private start-io-loop!)
(declare ^:private redis-pub)
(declare ^:private redis-sub)
(declare ^:private redis-unsub)
(declare ^:private start-io-loop)
(declare ^:private subscribe-to-topics)
(declare ^:private unsubscribe-channels)
(s/def ::cmd-ch sp/chan?)
(s/def ::rcv-ch sp/chan?)
(s/def ::pub-ch sp/chan?)
(s/def ::state ::us/agent)
(s/def ::pconn ::rds/connection-holder)
(s/def ::sconn ::rds/connection-holder)
(s/def ::msgbus
(s/keys :req [::cmd-ch ::rcv-ch ::pub-ch ::state ::pconn ::sconn ::wrk/executor]))
(defn msgbus?
[o]
(satisfies? IMsgBus o))
(defmethod ig/pre-init-spec ::msgbus [_]
(s/keys :req [::rds/redis ::wrk/executor]))
(sm/register!
{:type ::msgbus
:pred msgbus?})
(defmethod ig/prep-key ::msgbus
[_ cfg]
(-> cfg
(assoc ::buffer-size 128)
(assoc ::timeout (dt/duration {:seconds 30}))))
(defmethod ig/expand-key ::msgbus
[k v]
{k (-> (d/without-nils v)
(assoc ::buffer-size 128)
(assoc ::timeout (dt/duration {:seconds 30})))})
(def ^:private schema:params
[:map ::rds/redis ::wrk/executor])
(defmethod ig/assert-key ::msgbus
[_ params]
(assert (sm/check schema:params params)))
(defmethod ig/init-key ::msgbus
[_ {:keys [::buffer-size ::wrk/executor ::timeout ::rds/redis] :as cfg}]
@@ -66,46 +74,66 @@
:xf xform-prefix-topic)
state (agent {})
pconn (rds/connect redis :timeout timeout)
pconn (rds/connect redis :type :default :timeout timeout)
sconn (rds/connect redis :type :pubsub :timeout timeout)
msgbus (-> cfg
_ (set-error-handler! state #(l/error :cause % :hint "unexpected error on agent" ::l/sync? true))
_ (set-error-mode! state :continue)
cfg (-> cfg
(assoc ::pconn pconn)
(assoc ::sconn sconn)
(assoc ::cmd-ch cmd-ch)
(assoc ::rcv-ch rcv-ch)
(assoc ::pub-ch pub-ch)
(assoc ::state state)
(assoc ::wrk/executor executor))]
(assoc ::state state))
(set-error-handler! state #(l/error :cause % :hint "unexpected error on agent" ::l/sync? true))
(set-error-mode! state :continue)
io-thr (start-io-loop cfg)]
(assoc msgbus ::io-thr (start-io-loop! msgbus))))
(reify
java.lang.AutoCloseable
(close [_]
(px/interrupt! io-thr)
(sp/close! cmd-ch)
(sp/close! rcv-ch)
(sp/close! pub-ch)
(d/close! pconn)
(d/close! sconn))
IMsgBus
(-sub [_ topics chan]
(l/debug :hint "subscribe" :topics topics :chan (hash chan))
(send-via executor state subscribe-to-topics cfg topics chan))
(-pub [_ topic message]
(let [message (assoc message :topic topic)]
(sp/put! pub-ch {:topic topic :message message})))
(-purge [_ chans]
(l/debug :hint "purge" :chans (count chans))
(send-via executor state unsubscribe-channels cfg chans)))))
(defmethod ig/halt-key! ::msgbus
[_ msgbus]
(px/interrupt! (::io-thr msgbus))
(sp/close! (::cmd-ch msgbus))
(sp/close! (::rcv-ch msgbus))
(sp/close! (::pub-ch msgbus))
(d/close! (::pconn msgbus))
(d/close! (::sconn msgbus)))
[_ instance]
(d/close! instance))
(defn sub!
[{:keys [::state ::wrk/executor] :as cfg} & {:keys [topic topics chan]}]
[instance & {:keys [topic topics chan]}]
(assert (satisfies? IMsgBus instance) "expected valid msgbus instance")
(let [topics (into [] (map prefix-topic) (if topic [topic] topics))]
(l/debug :hint "subscribe" :topics topics :chan (hash chan))
(send-via executor state subscribe-to-topics cfg topics chan)
(-sub instance topics chan)
nil))
(defn pub!
[{::keys [pub-ch]} & {:as params}]
(sp/put! pub-ch params))
[instance & {:keys [topic message]}]
(assert (satisfies? IMsgBus instance) "expected valid msgbus instance")
(-pub instance topic message))
(defn purge!
[{:keys [::state ::wrk/executor] :as msgbus} chans]
(l/debug :hint "purge" :chans (count chans))
(send-via executor state unsubscribe-channels msgbus chans)
[instance chans]
(assert (satisfies? IMsgBus instance) "expected valid msgbus instance")
(assert (every? sp/chan? chans) "expected a seq of chans")
(-purge instance chans)
nil)
;; --- IMPL
@@ -118,7 +146,7 @@
(let [nsubs (if (nil? nsubs) #{chan} (conj nsubs chan))]
(when (= 1 (count nsubs))
(l/trace :hint "open subscription" :topic topic ::l/sync? true)
(redis-sub! cfg topic))
(redis-sub cfg topic))
nsubs))
(defn- disj-subscription
@@ -129,7 +157,7 @@
(let [nsubs (disj nsubs chan)]
(when (empty? nsubs)
(l/trace :hint "close subscription" :topic topic ::l/sync? true)
(redis-unsub! cfg topic))
(redis-unsub cfg topic))
nsubs))
(defn- subscribe-to-topics
@@ -170,7 +198,7 @@
(when-not (sp/offer! rcv-ch val)
(l/warn :msg "dropping message on subscription loop"))))))
(defn- process-input!
(defn- process-input
[{:keys [::state ::wrk/executor] :as cfg} topic message]
(let [chans (get-in @state [:topics topic])]
(when-let [closed (loop [chans (seq chans)
@@ -183,9 +211,9 @@
(send-via executor state unsubscribe-channels cfg closed))))
(defn start-io-loop!
(defn start-io-loop
[{:keys [::sconn ::rcv-ch ::pub-ch ::state ::wrk/executor] :as cfg}]
(rds/add-listener! sconn (create-listener rcv-ch))
(rds/add-listener sconn (create-listener rcv-ch))
(px/thread
{:name "penpot/msgbus/io-loop"
@@ -209,12 +237,12 @@
(identical? port rcv-ch)
(let [{:keys [topic message]} val]
(process-input! cfg topic message)
(process-input cfg topic message)
(recur))
(identical? port pub-ch)
(do
(redis-pub! cfg val)
(redis-pub cfg val)
(recur)))))
(catch InterruptedException _
@@ -230,13 +258,12 @@
(l/debug :hint "io-loop thread terminated")))))
(defn- redis-pub!
(defn- redis-pub
"Publish a message to the redis server. Asynchronous operation,
intended to be used in core.async go blocks."
[{:keys [::pconn] :as cfg} {:keys [topic message]}]
(try
(p/await! (rds/publish! pconn topic (t/encode message)))
(p/await! (rds/publish pconn topic (t/encode message)))
(catch InterruptedException cause
(throw cause))
(catch Throwable cause
@@ -244,23 +271,23 @@
:message message
:cause cause))))
(defn- redis-sub!
(defn- redis-sub
"Create redis subscription. Blocking operation, intended to be used
inside an agent."
[{:keys [::sconn] :as cfg} topic]
(try
(rds/subscribe! sconn topic)
(rds/subscribe sconn [topic])
(catch InterruptedException cause
(throw cause))
(catch Throwable cause
(l/trace :hint "exception on subscribing" :topic topic :cause cause))))
(defn- redis-unsub!
(defn- redis-unsub
"Removes redis subscription. Blocking operation, intended to be used
inside an agent."
[{:keys [::sconn] :as cfg} topic]
(try
(rds/unsubscribe! sconn topic)
(rds/unsubscribe sconn [topic])
(catch InterruptedException cause
(throw cause))
(catch Throwable cause

View File

@@ -6,11 +6,12 @@
(ns app.redis
"The msgbus abstraction implemented using redis as underlying backend."
(:refer-clojure :exclude [eval])
(:require
[app.common.data :as d]
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.metrics :as mtx]
[app.redis.script :as-alias rscript]
[app.util.cache :as cache]
@@ -18,13 +19,11 @@
[app.worker :as-alias wrk]
[clojure.core :as c]
[clojure.java.io :as io]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig]
[promesa.core :as p]
[promesa.exec :as px])
(:import
clojure.lang.IDeref
clojure.lang.MapEntry
io.lettuce.core.KeyValue
io.lettuce.core.RedisClient
@@ -53,79 +52,24 @@
(set! *warn-on-reflection* true)
(declare initialize-resources)
(declare shutdown-resources)
(declare connect*)
(declare ^:private initialize-resources)
(declare ^:private shutdown-resources)
(declare ^:private impl-eval)
(s/def ::timer
#(instance? Timer %))
(defprotocol IRedis
(-connect [_ options])
(-get-or-connect [_ key options]))
(s/def ::default-connection
#(or (instance? StatefulRedisConnection %)
(and (instance? IDeref %)
(instance? StatefulRedisConnection (deref %)))))
(defprotocol IConnection
(publish [_ topic message])
(rpush [_ key payload])
(blpop [_ timeout keys])
(eval [_ script]))
(s/def ::pubsub-connection
#(or (instance? StatefulRedisPubSubConnection %)
(and (instance? IDeref %)
(instance? StatefulRedisPubSubConnection (deref %)))))
(s/def ::connection
(s/or :default ::default-connection
:pubsub ::pubsub-connection))
(s/def ::connection-holder
(s/keys :req [::connection]))
(s/def ::redis-uri
#(instance? RedisURI %))
(s/def ::resources
#(instance? ClientResources %))
(s/def ::pubsub-listener
#(instance? RedisPubSubListener %))
(s/def ::uri ::us/not-empty-string)
(s/def ::timeout ::dt/duration)
(s/def ::connect? ::us/boolean)
(s/def ::io-threads ::us/integer)
(s/def ::worker-threads ::us/integer)
(s/def ::cache cache/cache?)
(s/def ::redis
(s/keys :req [::resources
::redis-uri
::timer
::mtx/metrics]
:opt [::connection
::cache]))
(defmethod ig/prep-key ::redis
[_ cfg]
(let [cpus (px/get-available-processors)
threads (max 1 (int (* cpus 0.2)))]
(merge {::timeout (dt/duration "10s")
::io-threads (max 3 threads)
::worker-threads (max 3 threads)}
(d/without-nils cfg))))
(defmethod ig/pre-init-spec ::redis [_]
(s/keys :req [::uri ::mtx/metrics]
:opt [::timeout
::connect?
::io-threads
::worker-threads]))
(defmethod ig/init-key ::redis
[_ {:keys [::connect?] :as cfg}]
(let [state (initialize-resources cfg)]
(cond-> state
connect? (assoc ::connection (connect* cfg {})))))
(defmethod ig/halt-key! ::redis
[_ state]
(shutdown-resources state))
(defprotocol IPubSubConnection
(add-listener [_ listener])
(subscribe [_ topics])
(unsubscribe [_ topics]))
(def default-codec
(RedisCodec/of StringCodec/UTF8 ByteArrayCodec/INSTANCE))
@@ -133,23 +77,76 @@
(def string-codec
(RedisCodec/of StringCodec/UTF8 StringCodec/UTF8))
(defn- create-cache
[{:keys [::wrk/executor] :as cfg}]
(letfn [(on-remove [key val cause]
(l/trace :hint "evict connection (cache)" :key key :reason cause)
(some-> val d/close!))]
(cache/create :executor executor
:on-remove on-remove
:keepalive "5m")))
(sm/register!
{:type ::connection
:pred #(satisfies? IConnection %)
:type-properties
{:title "connection"
:description "redis connection instance"}})
(sm/register!
{:type ::pubsub-connection
:pred #(satisfies? IPubSubConnection %)
:type-properties
{:title "connection"
:description "redis connection instance"}})
(defn redis?
[o]
(satisfies? IRedis o))
(sm/register!
{:type ::redis
:pred redis?})
(def ^:private schema:script
[:map {:title "script"}
[::rscript/name qualified-keyword?]
[::rscript/path ::sm/text]
[::rscript/keys {:optional true} [:vector :any]]
[::rscript/vals {:optional true} [:vector :any]]])
(def valid-script?
(sm/lazy-validator schema:script))
(defmethod ig/expand-key ::redis
[k v]
(let [cpus (px/get-available-processors)
threads (max 1 (int (* cpus 0.2)))]
{k (-> (d/without-nils v)
(assoc ::timeout (dt/duration "10s"))
(assoc ::io-threads (max 3 threads))
(assoc ::worker-threads (max 3 threads)))}))
(def ^:private schema:redis-params
[:map {:title "redis-params"}
::wrk/executor
::mtx/metrics
[::uri ::sm/uri]
[::worker-threads ::sm/int]
[::io-threads ::sm/int]
[::timeout ::dt/duration]])
(defmethod ig/assert-key ::redis
[_ params]
(assert (sm/check schema:redis-params params)))
(defmethod ig/init-key ::redis
[_ params]
(initialize-resources params))
(defmethod ig/halt-key! ::redis
[_ instance]
(d/close! instance))
(defn- initialize-resources
"Initialize redis connection resources"
[{:keys [::uri ::io-threads ::worker-threads ::connect?] :as cfg}]
(l/info :hint "initialize redis resources"
:uri uri
:io-threads io-threads
:worker-threads worker-threads
:connect? connect?)
[{:keys [::uri ::io-threads ::worker-threads ::wrk/executor ::mtx/metrics] :as params}]
(l/inf :hint "initialize redis resources"
:uri (str uri)
:io-threads io-threads
:worker-threads worker-threads)
(let [timer (HashedWheelTimer.)
resources (.. (DefaultClientResources/builder)
@@ -158,147 +155,134 @@
(timer ^Timer timer)
(build))
redis-uri (RedisURI/create ^String uri)
cfg (-> cfg
(assoc ::resources resources)
(assoc ::timer timer)
(assoc ::redis-uri redis-uri))]
redis-uri (RedisURI/create ^String (str uri))
(assoc cfg ::cache (create-cache cfg))))
shutdown (fn [client conn]
(ex/ignoring (.close ^StatefulConnection conn))
(ex/ignoring (.close ^RedisClient client))
(l/trc :hint "disconnect" :hid (hash client)))
(defn- shutdown-resources
[{:keys [::resources ::cache ::timer]}]
(cache/invalidate! cache)
on-remove (fn [key val cause]
(l/trace :hint "evict connection (cache)" :key key :reason cause)
(some-> val d/close!))
(when resources
(.shutdown ^ClientResources resources))
(when timer
(.stop ^Timer timer)))
(defn connect*
[{:keys [::resources ::redis-uri] :as state}
{:keys [timeout codec type]
:or {codec default-codec type :default}}]
(us/assert! ::resources resources)
(let [client (RedisClient/create ^ClientResources resources ^RedisURI redis-uri)
timeout (or timeout (::timeout state))
conn (case type
:default (.connect ^RedisClient client ^RedisCodec codec)
:pubsub (.connectPubSub ^RedisClient client ^RedisCodec codec))]
(l/trc :hint "connect" :hid (hash client))
(.setTimeout ^StatefulConnection conn ^Duration timeout)
cache (cache/create :executor executor
:on-remove on-remove
:keepalive "5m")]
(reify
IDeref
(deref [_] conn)
AutoCloseable
java.lang.AutoCloseable
(close [_]
(ex/ignoring (.close ^StatefulConnection conn))
(ex/ignoring (.shutdown ^RedisClient client))
(l/trc :hint "disconnect" :hid (hash client))))))
(ex/ignoring (cache/invalidate! cache))
(ex/ignoring (.shutdown ^ClientResources resources))
(ex/ignoring (.stop ^Timer timer)))
IRedis
(-get-or-connect [this key options]
(let [create (fn [_] (-connect this options))]
(cache/get cache key create)))
(-connect [_ options]
(let [timeout (or (:timeout options) (::timeout params))
codec (get options :codec default-codec)
type (get options :type :default)
client (RedisClient/create ^ClientResources resources
^RedisURI redis-uri)]
(l/trc :hint "connect" :hid (hash client))
(if (= type :pubsub)
(let [conn (.connectPubSub ^RedisClient client
^RedisCodec codec)]
(.setTimeout ^StatefulConnection conn
^Duration timeout)
(reify
IPubSubConnection
(add-listener [_ listener]
(assert (instance? RedisPubSubListener listener) "expected listener instance")
(.addListener ^StatefulRedisPubSubConnection conn
^RedisPubSubListener listener))
(subscribe [_ topics]
(try
(let [topics (into-array String (map str topics))
cmd (.sync ^StatefulRedisPubSubConnection conn)]
(.subscribe ^RedisPubSubCommands cmd topics))
(catch RedisCommandInterruptedException cause
(throw (InterruptedException. (ex-message cause))))))
(unsubscribe [_ topics]
(try
(let [topics (into-array String (map str topics))
cmd (.sync ^StatefulRedisPubSubConnection conn)]
(.unsubscribe ^RedisPubSubCommands cmd topics))
(catch RedisCommandInterruptedException cause
(throw (InterruptedException. (ex-message cause))))))
AutoCloseable
(close [_] (shutdown client conn))))
(let [conn (.connect ^RedisClient client ^RedisCodec codec)]
(.setTimeout ^StatefulConnection conn ^Duration timeout)
(reify
IConnection
(publish [_ topic message]
(assert (string? topic) "expected topic to be string")
(assert (bytes? message) "expected message to be a byte array")
(let [pcomm (.async ^StatefulRedisConnection conn)]
(.publish ^RedisAsyncCommands pcomm ^String topic ^bytes message)))
(rpush [_ key payload]
(assert (or (and (vector? payload)
(every? bytes? payload))
(bytes? payload)))
(try
(let [cmd (.sync ^StatefulRedisConnection conn)
data (if (vector? payload) payload [payload])
vals (make-array (. Class (forName "[B")) (count data))]
(loop [i 0 xs (seq data)]
(when xs
(aset ^"[[B" vals i ^bytes (first xs))
(recur (inc i) (next xs))))
(.rpush ^RedisCommands cmd
^String key
^"[[B" vals))
(catch RedisCommandInterruptedException cause
(throw (InterruptedException. (ex-message cause))))))
(blpop [_ timeout keys]
(try
(let [keys (into-array Object (map str keys))
cmd (.sync ^StatefulRedisConnection conn)
timeout (/ (double (inst-ms timeout)) 1000.0)]
(when-let [res (.blpop ^RedisCommands cmd
^double timeout
^"[Ljava.lang.String;" keys)]
(MapEntry/create
(.getKey ^KeyValue res)
(.getValue ^KeyValue res))))
(catch RedisCommandInterruptedException cause
(throw (InterruptedException. (ex-message cause))))))
(eval [_ script]
(assert (valid-script? script) "expected valid script")
(impl-eval conn metrics script))
AutoCloseable
(close [_] (shutdown client conn))))))))))
(defn connect
[state & {:as opts}]
(let [connection (connect* state opts)]
(-> state
(assoc ::connection connection)
(dissoc ::cache)
(vary-meta assoc `d/close! (fn [_] (d/close! connection))))))
[instance & {:as opts}]
(assert (satisfies? IRedis instance) "expected valid redis instance")
(-connect instance opts))
(defn get-or-connect
[{:keys [::cache] :as state} key options]
(us/assert! ::redis state)
(let [create (fn [_] (connect* state options))
connection (cache/get cache key create)]
(-> state
(dissoc ::cache)
(assoc ::connection connection))))
(defn add-listener!
[{:keys [::connection] :as conn} listener]
(us/assert! ::pubsub-connection connection)
(us/assert! ::pubsub-listener listener)
(.addListener ^StatefulRedisPubSubConnection @connection
^RedisPubSubListener listener)
conn)
(defn publish!
[{:keys [::connection]} topic message]
(us/assert! ::us/string topic)
(us/assert! ::us/bytes message)
(us/assert! ::default-connection connection)
(let [pcomm (.async ^StatefulRedisConnection @connection)]
(.publish ^RedisAsyncCommands pcomm ^String topic ^bytes message)))
(defn subscribe!
"Blocking operation, intended to be used on a thread/agent thread."
[{:keys [::connection]} & topics]
(us/assert! ::pubsub-connection connection)
(try
(let [topics (into-array String (map str topics))
cmd (.sync ^StatefulRedisPubSubConnection @connection)]
(.subscribe ^RedisPubSubCommands cmd topics))
(catch RedisCommandInterruptedException cause
(throw (InterruptedException. (ex-message cause))))))
(defn unsubscribe!
"Blocking operation, intended to be used on a thread/agent thread."
[{:keys [::connection]} & topics]
(us/assert! ::pubsub-connection connection)
(try
(let [topics (into-array String (map str topics))
cmd (.sync ^StatefulRedisPubSubConnection @connection)]
(.unsubscribe ^RedisPubSubCommands cmd topics))
(catch RedisCommandInterruptedException cause
(throw (InterruptedException. (ex-message cause))))))
(defn rpush!
[{:keys [::connection]} key payload]
(us/assert! ::default-connection connection)
(us/assert! (or (and (vector? payload)
(every? bytes? payload))
(bytes? payload)))
(try
(let [cmd (.sync ^StatefulRedisConnection @connection)
data (if (vector? payload) payload [payload])
vals (make-array (. Class (forName "[B")) (count data))]
(loop [i 0 xs (seq data)]
(when xs
(aset ^"[[B" vals i ^bytes (first xs))
(recur (inc i) (next xs))))
(.rpush ^RedisCommands cmd
^String key
^"[[B" vals))
(catch RedisCommandInterruptedException cause
(throw (InterruptedException. (ex-message cause))))))
(defn blpop!
[{:keys [::connection]} timeout & keys]
(us/assert! ::default-connection connection)
(try
(let [keys (into-array Object (map str keys))
cmd (.sync ^StatefulRedisConnection @connection)
timeout (/ (double (inst-ms timeout)) 1000.0)]
(when-let [res (.blpop ^RedisCommands cmd
^double timeout
^"[Ljava.lang.String;" keys)]
(MapEntry/create
(.getKey ^KeyValue res)
(.getValue ^KeyValue res))))
(catch RedisCommandInterruptedException cause
(throw (InterruptedException. (ex-message cause))))))
(defn open?
[{:keys [::connection]}]
(us/assert! ::pubsub-connection connection)
(.isOpen ^StatefulConnection @connection))
[instance key & {:as opts}]
(assert (satisfies? IRedis instance) "expected valid redis instance")
(-get-or-connect instance key opts))
(defn pubsub-listener
[& {:keys [on-message on-subscribe on-unsubscribe]}]
@@ -328,26 +312,10 @@
(on-unsubscribe nil topic count)))))
(def ^:private scripts-cache (atom {}))
(def noop-fn (constantly nil))
(s/def ::rscript/name qualified-keyword?)
(s/def ::rscript/path ::us/not-empty-string)
(s/def ::rscript/keys (s/every any? :kind vector?))
(s/def ::rscript/vals (s/every any? :kind vector?))
(s/def ::rscript/script
(s/keys :req [::rscript/name
::rscript/path]
:opt [::rscript/keys
::rscript/vals]))
(defn eval!
[{:keys [::mtx/metrics ::connection] :as state} script]
(us/assert! ::redis state)
(us/assert! ::default-connection connection)
(us/assert! ::rscript/script script)
(let [cmd (.async ^StatefulRedisConnection @connection)
(defn- impl-eval
[^StatefulRedisConnection connection metrics script]
(let [cmd (.async ^StatefulRedisConnection connection)
keys (into-array String (map str (::rscript/keys script)))
vals (into-array String (map str (::rscript/vals script)))
sname (::rscript/name script)]

View File

@@ -36,8 +36,8 @@
[cuerdas.core :as str]
[integrant.core :as ig]
[promesa.core :as p]
[ring.request :as rreq]
[ring.response :as rres]))
[yetti.request :as yreq]
[yetti.response :as yres]))
(s/def ::profile-id ::us/uuid)
@@ -64,16 +64,16 @@
response (if (fn? result)
(result request)
(let [result (rph/unwrap result)]
{::rres/status (::http/status mdata 200)
::rres/headers (::http/headers mdata {})
::rres/body result}))]
{::yres/status (::http/status mdata 200)
::yres/headers (::http/headers mdata {})
::yres/body result}))]
(-> response
(handle-response-transformation request mdata)
(handle-before-comple-hook mdata))))
(defn get-external-session-id
[request]
(when-let [session-id (rreq/get-header request "x-external-session-id")]
(when-let [session-id (yreq/get-header request "x-external-session-id")]
(when-not (or (> (count session-id) 256)
(= session-id "null")
(str/blank? session-id))
@@ -81,7 +81,7 @@
(defn- get-external-event-origin
[request]
(when-let [origin (rreq/get-header request "x-event-origin")]
(when-let [origin (yreq/get-header request "x-event-origin")]
(when-not (or (> (count origin) 256)
(= origin "null")
(str/blank? origin))
@@ -92,7 +92,7 @@
internal async flow into ring async flow."
[methods {:keys [params path-params method] :as request}]
(let [handler-name (:type path-params)
etag (rreq/get-header request "if-none-match")
etag (yreq/get-header request "if-none-match")
profile-id (or (::session/profile-id request)
(::actoken/profile-id request))
@@ -149,6 +149,13 @@
:hint "authentication required for this endpoint")
(f cfg params)))))
(defn- wrap-db-transaction
[_ f mdata]
(if (::db/transaction mdata)
(fn [cfg params]
(db/tx-run! cfg f params))
f))
(defn- wrap-audit
[_ f mdata]
(if (or (contains? cf/flags :webhooks)
@@ -178,41 +185,25 @@
(if-let [schema (::sm/params mdata)]
(let [validate (sm/validator schema)
explain (sm/explainer schema)
decode (sm/decoder schema)]
decode (sm/decoder schema sm/json-transformer)
encode (sm/encoder schema sm/json-transformer)]
(fn [cfg params]
(let [params (decode params)]
(if (validate params)
(f cfg params)
(let [result (f cfg params)]
(if (instance? clojure.lang.IObj result)
(vary-meta result assoc :encode/json encode)
result))
(let [params (d/without-qualified params)]
(ex/raise :type :validation
:code :params-validation
::sm/explain (explain params)))))))
f))
(defn- wrap-output-validation
[_ f mdata]
(if (contains? cf/flags :rpc-output-validation)
(or (when-let [schema (::sm/result mdata)]
(let [schema (if (sm/lazy-schema? schema)
schema
(sm/define schema))
validate (sm/validator schema)
explain (sm/explainer schema)]
(fn [cfg params]
(let [response (f cfg params)]
(when (map? response)
(when-not (validate response)
(ex/raise :type :validation
:code :data-validation
::sm/explain (explain response))))
response))))
f)
f))
(defn- wrap-all
[cfg f mdata]
(as-> f $
(wrap-db-transaction cfg $ mdata)
(cond/wrap cfg $ mdata)
(retry/wrap-retry cfg $ mdata)
(climit/wrap cfg $ mdata)
@@ -220,7 +211,6 @@
(rlimit/wrap cfg $ mdata)
(wrap-audit cfg $ mdata)
(wrap-spec-conform cfg $ mdata)
(wrap-output-validation cfg $ mdata)
(wrap-params-validation cfg $ mdata)
(wrap-authentication cfg $ mdata)))
@@ -260,39 +250,49 @@
'app.rpc.commands.projects
'app.rpc.commands.search
'app.rpc.commands.teams
'app.rpc.commands.teams-invitations
'app.rpc.commands.verify-token
'app.rpc.commands.viewer
'app.rpc.commands.webhooks)
(map (partial process-method cfg))
(into {}))))
(defmethod ig/pre-init-spec ::methods [_]
(s/keys :req [::session/manager
::http.client/client
::db/pool
::mbus/msgbus
::ldap/provider
::sto/storage
::mtx/metrics
::setup/props]
:opt [::climit
::rlimit]))
(def ^:private schema:methods-params
[:map {:title "methods-params"}
::session/manager
::http.client/client
::db/pool
::mbus/msgbus
::sto/storage
::mtx/metrics
[::ldap/provider [:maybe ::ldap/provider]]
[::climit [:maybe ::climit]]
[::rlimit [:maybe ::rlimit]]
::setup/props])
(defmethod ig/assert-key ::methods
[_ params]
(assert (sm/check schema:methods-params params)))
(defmethod ig/init-key ::methods
[_ cfg]
(let [cfg (d/without-nils cfg)]
(resolve-command-methods cfg)))
(s/def ::methods
(s/map-of keyword? (s/tuple map? fn?)))
(def ^:private schema:methods
[:map-of :keyword [:tuple :map ::sm/fn]])
(s/def ::routes vector?)
(sm/register! ::methods schema:methods)
(defmethod ig/pre-init-spec ::routes [_]
(s/keys :req [::methods
::db/pool
::setup/props
::session/manager]))
(def ^:private valid-methods?
(sm/validator schema:methods))
(defmethod ig/assert-key ::routes
[_ params]
(assert (db/pool? (::db/pool params)) "expect valid database pool")
(assert (some? (::setup/props params)))
(assert (session/manager? (::session/manager params)) "expect valid session manager")
(assert (valid-methods? (::methods params)) "expect valid methods map"))
(defmethod ig/init-key ::routes
[_ {:keys [::methods] :as cfg}]

View File

@@ -10,18 +10,15 @@
(:require
[app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.spec :as us]
[app.config :as cf]
[app.common.schema :as sm]
[app.metrics :as mtx]
[app.rpc :as-alias rpc]
[app.rpc.climit.config :as-alias config]
[app.util.cache :as cache]
[app.util.services :as-alias sv]
[app.util.time :as dt]
[app.worker :as-alias wrk]
[clojure.edn :as edn]
[clojure.set :as set]
[clojure.spec.alpha :as s]
[datoteka.fs :as fs]
[integrant.core :as ig]
[promesa.exec :as px]
@@ -32,6 +29,62 @@
(set! *warn-on-reflection* true)
(declare ^:private impl-invoke)
(declare ^:private id->str)
(declare ^:private create-cache)
(defprotocol IConcurrencyLimiter
(^:private get-config [_ limit-id] "get a config for a key")
(^:private invoke [_ config handler] "invoke a handler for a config"))
(sm/register!
{:type ::rpc/climit
:pred #(satisfies? IConcurrencyLimiter %)})
(def ^:private schema:config
[:map-of :keyword
[:map
[::id {:optional true} :keyword]
[::key {:optional true} :any]
[::label {:optional true} ::sm/text]
[::params {:optional true} :map]
[::permits {:optional true} ::sm/int]
[::queue {:optional true} ::sm/int]
[::timeout {:optional true} ::sm/int]]])
(def ^:private check-config
(sm/check-fn schema:config))
(def ^:private schema:climit-params
[:map
::mtx/metrics
::wrk/executor
[::enabled {:optional true} ::sm/boolean]
[::config {:optional true} ::fs/path]])
(defmethod ig/assert-key ::rpc/climit
[_ params]
(assert (sm/valid? schema:climit-params params)))
(defmethod ig/init-key ::rpc/climit
[_ {:keys [::config ::enabled ::mtx/metrics] :as cfg}]
(when enabled
(when-let [params (some->> config slurp edn/read-string check-config)]
(l/inf :hint "initializing concurrency limit" :config (str config))
(let [params (reduce-kv (fn [result k v]
(assoc result k (assoc v ::id k)))
params
params)
cache (create-cache cfg)]
(reify
IConcurrencyLimiter
(get-config [_ id]
(get params id))
(invoke [_ config handler]
(impl-invoke metrics cache config handler)))))))
(defn- id->str
([id]
(-> (str id)
@@ -41,59 +94,23 @@
(str (-> (str id) (subs 1)) "/" key)
(id->str id))))
(defn- create-cache
[{:keys [::wrk/executor]}]
(letfn [(on-remove [key _ cause]
(let [[id skey] key]
(l/trc :hint "disposed" :id (id->str id skey) :reason (str cause))))]
(cache/create :executor executor
:on-remove on-remove
:keepalive "5m")))
(s/def ::config/permits ::us/integer)
(s/def ::config/queue ::us/integer)
(s/def ::config/timeout ::us/integer)
(s/def ::config
(s/map-of keyword?
(s/keys :opt-un [::config/permits
::config/queue
::config/timeout])))
(defmethod ig/prep-key ::rpc/climit
[_ cfg]
(assoc cfg ::path (cf/get :rpc-climit-config)))
(s/def ::path ::fs/path)
(defmethod ig/pre-init-spec ::rpc/climit [_]
(s/keys :req [::mtx/metrics ::wrk/executor ::path]))
(defmethod ig/init-key ::rpc/climit
[_ {:keys [::path ::mtx/metrics] :as cfg}]
(when (contains? cf/flags :rpc-climit)
(when-let [params (some->> path slurp edn/read-string)]
(l/inf :hint "initializing concurrency limit" :config (str path))
(us/verify! ::config params)
{::cache (create-cache cfg)
::config params
::mtx/metrics metrics})))
(s/def ::cache cache/cache?)
(s/def ::instance
(s/keys :req [::cache ::config]))
(s/def ::rpc/climit
(s/nilable ::instance))
(defn- create-limiter
[config [id skey]]
(l/trc :hint "created" :id (id->str id skey))
[config id]
(l/trc :hint "created" :id id)
(pbh/create :permits (or (:permits config) (:concurrency config))
:queue (or (:queue config) (:queue-size config))
:timeout (:timeout config)
:type :semaphore))
(defn- create-cache
[{:keys [::wrk/executor]}]
(letfn [(on-remove [id _ cause]
(l/trc :hint "disposed" :id id :reason (str cause)))]
(cache/create :executor executor
:on-remove on-remove
:keepalive "5m")))
(defn measure!
(defn- measure
[metrics mlabels stats elapsed]
(let [mpermits (:max-permits stats)
permits (:permits stats)
@@ -117,8 +134,14 @@
:val (inst-ms elapsed)
:labels mlabels))))
(defn log!
[action req-id stats limit-id limit-label params elapsed]
(defn- prepare-params-for-debug
[params]
(-> (select-keys params [::rpc/profile-id :file-id :profile-id])
(set/rename-keys {::rpc/profile-id :profile-id})
(update-vals str)))
(defn- log
[action req-id stats limit-id limit-label limit-params elapsed]
(let [mpermits (:max-permits stats)
queue (:queue stats)
queue (- queue mpermits)
@@ -132,37 +155,42 @@
:label limit-label
:queue queue
:elapsed (some-> elapsed dt/format-duration)
:params (-> (select-keys params [::rpc/profile-id :file-id :profile-id])
(set/rename-keys {::rpc/profile-id :profile-id})
(update-vals str)))))
:params @limit-params)))
(def ^:private idseq (AtomicLong. 0))
(defn- invoke
[limiter metrics limit-id limit-key limit-label handler params]
(let [tpoint (dt/tpoint)
mlabels (into-array String [(id->str limit-id)])
limit-id (id->str limit-id limit-key)
stats (pbh/get-stats limiter)
req-id (.incrementAndGet ^AtomicLong idseq)]
(defn- impl-invoke
[metrics cache config handler]
(let [limit-id (::id config)
limit-key (::key config)
limit-label (::label config)
limit-params (delay
(prepare-params-for-debug
(::params config)))
mlabels (into-array String [(id->str limit-id)])
limit-id (id->str limit-id limit-key)
limiter (cache/get cache limit-id (partial create-limiter config))
tpoint (dt/tpoint)
req-id (.incrementAndGet ^AtomicLong idseq)]
(try
(measure! metrics mlabels stats nil)
(log! "enqueued" req-id stats limit-id limit-label params nil)
(let [stats (pbh/get-stats limiter)]
(measure metrics mlabels stats nil)
(log "enqueued" req-id stats limit-id limit-label limit-params nil))
(px/invoke! limiter (fn []
(let [elapsed (tpoint)
stats (pbh/get-stats limiter)]
(measure! metrics mlabels stats elapsed)
(log! "acquired" req-id stats limit-id limit-label params elapsed)
(handler params))))
(measure metrics mlabels stats elapsed)
(log "acquired" req-id stats limit-id limit-label limit-params elapsed)
(handler))))
(catch ExceptionInfo cause
(let [{:keys [type code]} (ex-data cause)]
(if (= :bulkhead-error type)
(let [elapsed (tpoint)]
(log! "rejected" req-id stats limit-id limit-label params elapsed)
(let [elapsed (tpoint)
stats (pbh/get-stats limiter)]
(log "rejected" req-id stats limit-id limit-label limit-params elapsed)
(ex/raise :type :concurrency-limit
:code code
:hint "concurrency limit reached"
@@ -173,8 +201,8 @@
(let [elapsed (tpoint)
stats (pbh/get-stats limiter)]
(measure! metrics mlabels stats nil)
(log! "finished" req-id stats limit-id limit-label params elapsed))))))
(measure metrics mlabels stats nil)
(log "finished" req-id stats limit-id limit-label limit-params elapsed))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; MIDDLEWARE
@@ -204,71 +232,70 @@
(throw (IllegalArgumentException. "unable to normalize limit")))))
(defn wrap
[{:keys [::rpc/climit ::mtx/metrics]} handler mdata]
(let [cache (::cache climit)
config (::config climit)
label (::sv/name mdata)]
[cfg handler {label ::sv/name :as mdata}]
(if-let [climit (::rpc/climit cfg)]
(reduce (fn [handler [limit-id key-fn]]
(if-let [config (get-config climit limit-id)]
(let [key-fn (or key-fn noop-fn)]
(l/trc :hint "instrumenting method"
:method label
:limit (id->str limit-id)
:timeout (:timeout config)
:permits (:permits config)
:queue (:queue config)
:keyed (not= key-fn nil))
(if climit
(reduce (fn [handler [limit-id key-fn]]
(if-let [config (get config limit-id)]
(let [key-fn (or key-fn noop-fn)]
(l/trc :hint "instrumenting method"
:method label
:limit (id->str limit-id)
:timeout (:timeout config)
:permits (:permits config)
:queue (:queue config)
:keyed (not= key-fn noop-fn))
(if (and (= key-fn ::rpc/profile-id)
(false? (::rpc/auth mdata true)))
(if (and (= key-fn ::rpc/profile-id)
(false? (::rpc/auth mdata true)))
;; We don't enforce by-profile limit on methods that does
;; not require authentication
handler
;; We don't enforce by-profile limit on methods that does
;; not require authentication
handler
(fn [cfg params]
(let [config (-> config
(assoc ::key (key-fn params))
(assoc ::label label)
;; NOTE: only used for debugging output
(assoc ::params params))]
(invoke climit config (partial handler cfg params))))))
(fn [cfg params]
(let [limit-key (key-fn params)
cache-key [limit-id limit-key]
limiter (cache/get cache cache-key (partial create-limiter config))
handler (partial handler cfg)]
(invoke limiter metrics limit-id limit-key label handler params)))))
(do
(l/wrn :hint "no config found for specified queue" :id (id->str limit-id))
handler)))
handler
(concat global-limits (get-limits mdata)))
(do
(l/wrn :hint "no config found for specified queue" :id (id->str limit-id))
handler)))
handler
(concat global-limits (get-limits mdata)))
handler)))
handler))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PUBLIC API
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- build-exec-chain
[{:keys [::label ::rpc/climit ::mtx/metrics] :as cfg} f]
(let [config (get climit ::config)
cache (get climit ::cache)]
(reduce (fn [handler [limit-id limit-key :as ckey]]
(if-let [config (get config limit-id)]
[{:keys [::label ::rpc/climit] :as cfg} f]
(reduce (fn [handler [limit-id limit-key]]
(if-let [config (get-config climit limit-id)]
(let [config (-> config
(assoc ::key limit-key)
(assoc ::label label))]
(fn [cfg params]
(let [limiter (cache/get cache ckey (partial create-limiter config))
handler (partial handler cfg)]
(invoke limiter metrics limit-id limit-key label handler params)))
(do
(l/wrn :hint "config not found" :label label :id limit-id)
f)))
f
(get-limits cfg))))
(let [config (assoc config ::params params)]
(invoke climit config (partial handler cfg params)))))
(do
(l/wrn :hint "config not found" :label label :id limit-id)
f)))
f
(get-limits cfg)))
(defn invoke!
"Run a function in context of climit.
Intended to be used in virtual threads."
[{:keys [::executor] :as cfg} f params]
(let [f (if (some? executor)
(fn [cfg params] (px/await! (px/submit! executor (fn [] (f cfg params)))))
f)
f (build-exec-chain cfg f)]
[{:keys [::executor ::rpc/climit] :as cfg} f params]
(let [f (if climit
(let [f (if (some? executor)
(fn [cfg params] (px/await! (px/submit! executor (fn [] (f cfg params)))))
f)]
(build-exec-chain cfg f))
f)]
(f cfg params)))

View File

@@ -6,7 +6,7 @@
(ns app.rpc.commands.access-token
(:require
[app.common.spec :as us]
[app.common.schema :as sm]
[app.common.uuid :as uuid]
[app.db :as db]
[app.main :as-alias main]
@@ -16,8 +16,7 @@
[app.setup :as-alias setup]
[app.tokens :as tokens]
[app.util.services :as sv]
[app.util.time :as dt]
[clojure.spec.alpha :as s]))
[app.util.time :as dt]))
(defn- decode-row
[row]
@@ -31,20 +30,19 @@
:tid token-id
:iat created-at})
expires-at (some-> expiration dt/in-future)]
expires-at (some-> expiration dt/in-future)
token (db/insert! conn :access-token
{:id token-id
:name name
:token token
:profile-id profile-id
:created-at created-at
:updated-at created-at
:expires-at expires-at
:perms (db/create-array conn "text" [])})]
(decode-row token)))
(db/insert! conn :access-token
{:id token-id
:name name
:token token
:profile-id profile-id
:created-at created-at
:updated-at created-at
:expires-at expires-at
:perms (db/create-array conn "text" [])})))
(defn repl-create-access-token
(defn repl:create-access-token
[{:keys [::db/pool] :as system} profile-id name expiration]
(db/with-atomic [conn pool]
(let [props (:app.setup/props system)]
@@ -53,40 +51,38 @@
name
expiration))))
(s/def ::name ::us/not-empty-string)
(s/def ::expiration ::dt/duration)
(s/def ::create-access-token
(s/keys :req [::rpc/profile-id]
:req-un [::name]
:opt-un [::expiration]))
(def ^:private schema:create-access-token
[:map {:title "create-access-token"}
[:name [:string {:max 250 :min 1}]]
[:expiration {:optional true} ::dt/duration]])
(sv/defmethod ::create-access-token
{::doc/added "1.18"}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id name expiration]}]
(db/with-atomic [conn pool]
(let [cfg (assoc cfg ::db/conn conn)]
(quotes/check-quote! conn
{::quotes/id ::quotes/access-tokens-per-profile
::quotes/profile-id profile-id})
(-> (create-access-token cfg profile-id name expiration)
(decode-row)))))
{::doc/added "1.18"
::sm/params schema:create-access-token}
[cfg {:keys [::rpc/profile-id name expiration]}]
(s/def ::delete-access-token
(s/keys :req [::rpc/profile-id]
:req-un [::us/id]))
(quotes/check! cfg {::quotes/id ::quotes/access-tokens-per-profile
::quotes/profile-id profile-id})
(db/tx-run! cfg create-access-token profile-id name expiration))
(def ^:private schema:delete-access-token
[:map {:title "delete-access-token"}
[:id ::sm/uuid]])
(sv/defmethod ::delete-access-token
{::doc/added "1.18"}
{::doc/added "1.18"
::sm/params schema:delete-access-token}
[{:keys [::db/pool]} {:keys [::rpc/profile-id id]}]
(db/delete! pool :access-token {:id id :profile-id profile-id})
nil)
(s/def ::get-access-tokens
(s/keys :req [::rpc/profile-id]))
(def ^:private schema:get-access-tokens
[:map {:title "get-access-tokens"}])
(sv/defmethod ::get-access-tokens
{::doc/added "1.18"}
{::doc/added "1.18"
::sm/params schema:get-access-tokens}
[{:keys [::db/pool]} {:keys [::rpc/profile-id]}]
(->> (db/query pool :access-token
{:profile-id profile-id}

View File

@@ -27,9 +27,11 @@
[app.rpc.doc :as-alias doc]
[app.rpc.helpers :as rph]
[app.setup :as-alias setup]
[app.setup.welcome-file :refer [create-welcome-file]]
[app.tokens :as tokens]
[app.util.services :as sv]
[app.util.time :as dt]
[app.worker :as wrk]
[cuerdas.core :as str]))
(def schema:password
@@ -180,10 +182,11 @@
(defn- validate-register-attempt!
[cfg params]
(when-not (contains? cf/flags :registration)
(when-not (contains? params :invitation-token)
(ex/raise :type :restriction
:code :registration-disabled)))
(when (or
(not (contains? cf/flags :registration))
(not (contains? cf/flags :login-with-password)))
(ex/raise :type :restriction
:code :registration-disabled))
(when (contains? params :invitation-token)
(let [invitation (tokens/verify (::setup/props cfg)
@@ -240,6 +243,7 @@
params (d/without-nils params)
token (tokens/generate (::setup/props cfg) params)]
(with-meta {:token token}
{::audit/profile-id uuid/zero})))
@@ -282,6 +286,7 @@
is-demo (:is-demo params false)
is-muted (:is-muted params false)
is-active (:is-active params false)
theme (:theme params nil)
email (str/lower email)
params {:id id
@@ -292,6 +297,7 @@
:password password
:deleted-at (:deleted-at params)
:props props
:theme theme
:is-active is-active
:is-muted is-muted
:is-demo is-demo}]
@@ -347,30 +353,45 @@
:extra-data ptoken})))
(defn register-profile
[{:keys [::db/conn] :as cfg} {:keys [token fullname] :as params}]
(let [claims (tokens/verify (::setup/props cfg) {:token token :iss :prepared-register})
[{:keys [::db/conn ::wrk/executor] :as cfg} {:keys [token fullname theme] :as params}]
(let [theme (when (= theme "light") theme)
claims (tokens/verify (::setup/props cfg) {:token token :iss :prepared-register})
params (-> claims
(into params)
(assoc :fullname fullname))
(assoc :fullname fullname)
(assoc :theme theme))
profile (if-let [profile-id (:profile-id claims)]
(profile/get-profile conn profile-id)
(let [is-active (or (boolean (:is-active claims))
(not (contains? cf/flags :email-verification)))
params (-> params
(assoc :is-active is-active)
(update :password #(profile/derive-password cfg %)))]
(->> (create-profile! conn params)
(create-profile-rels! conn))))
;; NOTE: we first try to match existing profile
;; by email, that in normal circumstances will
;; not return anything, but when a user tries to
;; reuse the same token multiple times, we need
;; to detect if the profile is already registered
(or (profile/get-profile-by-email conn (:email claims))
(let [is-active (or (boolean (:is-active claims))
(not (contains? cf/flags :email-verification)))
params (-> params
(assoc :is-active is-active)
(update :password #(profile/derive-password cfg %)))
profile (->> (create-profile! conn params)
(create-profile-rels! conn))]
(vary-meta profile assoc :created true))))
;; When no profile-id comes on claims means a new register
created? (not (:profile-id claims))
created? (-> profile meta :created true?)
invitation (when-let [token (:invitation-token params)]
(tokens/verify (::setup/props cfg) {:token token :iss :team-invitation}))
props (audit/profile->props profile)]
props (-> (audit/profile->props profile)
(assoc :from-invitation (some? invitation)))
create-welcome-file-when-needed
(fn []
(when (:create-welcome-file params)
(let [cfg (dissoc cfg ::db/conn)]
(wrk/submit! executor (create-welcome-file cfg profile)))))]
(cond
;; When profile is blocked, we just ignore it and return plain data
(:is-blocked profile)
@@ -407,6 +428,7 @@
(if (:is-active profile)
(-> (profile/strip-private-attrs profile)
(rph/with-transform (session/create-fn cfg (:id profile)))
(rph/with-defer create-welcome-file-when-needed)
(rph/with-meta
{::audit/replace-props props
::audit/context {:action "login"}
@@ -416,19 +438,21 @@
(when-not (eml/has-reports? conn (:email profile))
(send-email-verification! cfg profile))
(rph/with-meta {:email (:email profile)}
{::audit/replace-props props
::audit/context {:action "email-verification"}
::audit/profile-id (:id profile)})))
(-> {:email (:email profile)}
(rph/with-defer create-welcome-file-when-needed)
(rph/with-meta
{::audit/replace-props props
::audit/context {:action "email-verification"}
::audit/profile-id (:id profile)}))))
:else
(let [elapsed? (elapsed-verify-threshold? profile)
complaints? (eml/has-reports? conn (:email profile))
action (if complaints?
"ignore-because-complaints"
(if elapsed?
"resend-email-verification"
"ignore"))]
(let [elapsed? (elapsed-verify-threshold? profile)
reports? (eml/has-reports? conn (:email profile))
action (if reports?
"ignore-because-complaints"
(if elapsed?
"resend-email-verification"
"ignore"))]
(l/wrn :hint "repeated registry detected"
:profile-id (str (:id profile))
@@ -450,7 +474,9 @@
(def schema:register-profile
[:map {:title "register-profile"}
[:token schema:token]
[:fullname [::sm/word-string {:max 100}]]])
[:fullname [::sm/word-string {:max 100}]]
[:theme {:optional true} [:string {:max 10}]]
[:create-welcome-file {:optional true} :boolean]])
(sv/defmethod ::register-profile
{::rpc/auth false
@@ -522,7 +548,6 @@
(create-recovery-token)
(send-email-notification conn)))))))
(def schema:request-profile-recovery
[:map {:title "request-profile-recovery"}
[:email ::sm/email]])

View File

@@ -8,6 +8,7 @@
(:refer-clojure :exclude [assert])
(:require
[app.binfile.v1 :as bf.v1]
[app.binfile.v3 :as bf.v3]
[app.common.logging :as l]
[app.common.schema :as sm]
[app.db :as db]
@@ -24,51 +25,103 @@
[app.util.time :as dt]
[app.worker :as-alias wrk]
[promesa.exec :as px]
[ring.response :as rres]))
[yetti.response :as yres]))
(set! *warn-on-reflection* true)
;; --- Command: export-binfile
(def ^:private schema:export-binfile
(def ^:private
schema:export-binfile
[:map {:title "export-binfile"}
[:name :string]
[:name [:string {:max 250}]]
[:file-id ::sm/uuid]
[:include-libraries :boolean]
[:embed-assets :boolean]])
[:version {:optional true} ::sm/int]
[:include-libraries ::sm/boolean]
[:embed-assets ::sm/boolean]])
(defn stream-export-v1
[cfg {:keys [file-id include-libraries embed-assets] :as params}]
(yres/stream-body
(fn [_ output-stream]
(try
(-> cfg
(assoc ::bf.v1/ids #{file-id})
(assoc ::bf.v1/embed-assets embed-assets)
(assoc ::bf.v1/include-libraries include-libraries)
(bf.v1/export-files! output-stream))
(catch Throwable cause
(l/err :hint "exception on exporting file"
:file-id (str file-id)
:cause cause))))))
(defn stream-export-v3
[cfg {:keys [file-id include-libraries embed-assets] :as params}]
(yres/stream-body
(fn [_ output-stream]
(try
(-> cfg
(assoc ::bf.v3/ids #{file-id})
(assoc ::bf.v3/embed-assets embed-assets)
(assoc ::bf.v3/include-libraries include-libraries)
(bf.v3/export-files! output-stream))
(catch Throwable cause
(l/err :hint "exception on exporting file"
:file-id (str file-id)
:cause cause))))))
(sv/defmethod ::export-binfile
"Export a penpot file in a binary format."
{::doc/added "1.15"
::webhooks/event? true
::sm/result schema:export-binfile}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id include-libraries embed-assets] :as params}]
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id version file-id] :as params}]
(files/check-read-permissions! pool profile-id file-id)
(fn [_]
{::rres/status 200
::rres/headers {"content-type" "application/octet-stream"}
::rres/body (reify rres/StreamableResponseBody
(-write-body-to-stream [_ _ output-stream]
(try
(-> cfg
(assoc ::bf.v1/ids #{file-id})
(assoc ::bf.v1/embed-assets embed-assets)
(assoc ::bf.v1/include-libraries include-libraries)
(bf.v1/export-files! output-stream))
(catch Throwable cause
(l/err :hint "exception on exporting file"
:file-id (str file-id)
:cause cause)))))}))
(let [version (or version 1)
body (case (int version)
1 (stream-export-v1 cfg params)
2 (throw (ex-info "not-implemented" {}))
3 (stream-export-v3 cfg params))]
{::yres/status 200
::yres/headers {"content-type" "application/octet-stream"}
::yres/body body})))
;; --- Command: import-binfile
(defn- import-binfile-v1
[{:keys [::wrk/executor] :as cfg} {:keys [project-id profile-id name file]}]
(let [cfg (-> cfg
(assoc ::bf.v1/project-id project-id)
(assoc ::bf.v1/profile-id profile-id)
(assoc ::bf.v1/name name)
(assoc ::bf.v1/input (:path file)))]
;; NOTE: the importation process performs some operations that are
;; not very friendly with virtual threads, and for avoid
;; unexpected blocking of other concurrent operations we dispatch
;; that operation to a dedicated executor.
(px/invoke! executor (partial bf.v1/import-files! cfg))))
(defn- import-binfile-v3
[{:keys [::wrk/executor] :as cfg} {:keys [project-id profile-id name file]}]
(let [cfg (-> cfg
(assoc ::bf.v3/project-id project-id)
(assoc ::bf.v3/profile-id profile-id)
(assoc ::bf.v3/name name)
(assoc ::bf.v3/input (:path file)))]
;; NOTE: the importation process performs some operations that are
;; not very friendly with virtual threads, and for avoid
;; unexpected blocking of other concurrent operations we dispatch
;; that operation to a dedicated executor.
(px/invoke! executor (partial bf.v3/import-files! cfg))))
(defn- import-binfile
[{:keys [::wrk/executor ::bf.v1/project-id ::db/pool] :as cfg} input]
;; NOTE: the importation process performs some operations that
;; are not very friendly with virtual threads, and for avoid
;; unexpected blocking of other concurrent operations we
;; dispatch that operation to a dedicated executor.
(let [result (px/invoke! executor (partial bf.v1/import-files! cfg input))]
[{:keys [::db/pool] :as cfg} {:keys [project-id version] :as params}]
(let [result (case (int version)
1 (import-binfile-v1 cfg params)
3 (import-binfile-v3 cfg params))]
(db/update! pool :project
{:modified-at (dt/now)}
{:id project-id})
@@ -76,8 +129,10 @@
(def ^:private schema:import-binfile
[:map {:title "import-binfile"}
[:name :string]
[:name [:or [:string {:max 250}]
[:map-of ::sm/uuid [:string {:max 250}]]]]
[:project-id ::sm/uuid]
[:version {:optional true} ::sm/int]
[:file ::media/upload]])
(sv/defmethod ::import-binfile
@@ -86,12 +141,11 @@
::webhooks/event? true
::sse/stream? true
::sm/params schema:import-binfile}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id name project-id file] :as params}]
(projects/check-read-permissions! pool profile-id project-id)
(let [cfg (-> cfg
(assoc ::bf.v1/project-id project-id)
(assoc ::bf.v1/profile-id profile-id)
(assoc ::bf.v1/name name))]
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id project-id version] :as params}]
(projects/check-edition-permissions! pool profile-id project-id)
(let [params (-> params
(assoc :profile-id profile-id)
(assoc :version (or version 1)))]
(with-meta
(sse/response #(import-binfile cfg (:path file)))
(sse/response (partial import-binfile cfg params))
{::audit/props {:file nil}})))

View File

@@ -71,10 +71,15 @@
[conn comment-id & {:as opts}]
(db/get-by-id conn :comment comment-id opts))
(def ^:private sql:get-next-seqn
"SELECT (f.comment_thread_seqn + 1) AS next_seqn
FROM file AS f
WHERE f.id = ?
FOR UPDATE")
(defn- get-next-seqn
[conn file-id]
(let [sql "select (f.comment_thread_seqn + 1) as next_seqn from file as f where f.id = ?"
res (db/exec-one! conn [sql file-id])]
(let [res (db/exec-one! conn [sql:get-next-seqn file-id])]
(:next-seqn res)))
(def sql:upsert-comment-thread-status
@@ -292,7 +297,7 @@
[:map {:title "create-comment-thread"}
[:file-id ::sm/uuid]
[:position ::gpt/point]
[:content :string]
[:content [:string {:max 750}]]
[:page-id ::sm/uuid]
[:frame-id ::sm/uuid]
[:share-id {:optional true} [:maybe ::sm/uuid]]])
@@ -304,38 +309,43 @@
::rtry/when rtry/conflict-exception?
::sm/params schema:create-comment-thread}
[cfg {:keys [::rpc/profile-id ::rpc/request-at file-id page-id share-id position content frame-id]}]
(files/check-comment-permissions! cfg profile-id file-id share-id)
(db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}]
(files/check-comment-permissions! cfg profile-id file-id share-id)
(let [{:keys [team-id project-id page-name]} (get-file conn file-id page-id)]
(let [{:keys [team-id project-id page-name]} (get-file cfg file-id page-id)]
(run! (partial quotes/check-quote! cfg)
(list {::quotes/id ::quotes/comment-threads-per-file
::quotes/profile-id profile-id
::quotes/team-id team-id
::quotes/project-id project-id
::quotes/file-id file-id}
{::quotes/id ::quotes/comments-per-file
::quotes/profile-id profile-id
::quotes/team-id team-id
::quotes/project-id project-id
::quotes/file-id file-id}))
(-> cfg
(assoc ::quotes/profile-id profile-id)
(assoc ::quotes/team-id team-id)
(assoc ::quotes/project-id project-id)
(assoc ::quotes/file-id file-id)
(quotes/check! {::quotes/id ::quotes/comment-threads-per-file}
{::quotes/id ::quotes/comments-per-file}))
(create-comment-thread conn {:created-at request-at
:profile-id profile-id
:file-id file-id
:page-id page-id
:page-name page-name
:position position
:content content
:frame-id frame-id})))))
(let [params {:created-at request-at
:profile-id profile-id
:file-id file-id
:page-id page-id
:page-name page-name
:position position
:content content
:frame-id frame-id}
thread (db/tx-run! cfg create-comment-thread params)]
(vary-meta thread assoc ::audit/props thread))))
(defn- create-comment-thread
[conn {:keys [profile-id file-id page-id page-name created-at position content frame-id]}]
[{:keys [::db/conn] :as cfg}
{:keys [profile-id file-id page-id page-name created-at position content frame-id]}]
(let [;; NOTE: we take the next seq number from a separate query
;; because we need to lock the file for avoid race conditions
;; FIXME: this method touches and locks the file table,which
;; is already heavy-update tablel; we need to think on move
;; the sequence state management to a different table or
;; different storage (example: redis) for alivate the update
;; pression on the file table
(let [;; NOTE: we take the next seq number from a separate query because the whole
;; operation can be retried on conflict, and in this case the new seq shold be
;; retrieved from the database.
seqn (get-next-seqn conn file-id)
thread-id (uuid/next)
thread (db/insert! conn :comment-thread
@@ -364,7 +374,8 @@
;; Optimistic update of current seq number on file.
(db/update! conn :file
{:comment-thread-seqn seqn}
{:id file-id})
{:id file-id}
{::db/return-keys false})
(-> thread
(select-keys [:id :file-id :page-id])
@@ -387,7 +398,6 @@
(files/check-comment-permissions! conn profile-id file-id share-id)
(upsert-comment-thread-status! conn profile-id id)))))
;; --- COMMAND: Update Comment Thread
(def ^:private
@@ -418,7 +428,7 @@
schema:create-comment
[:map {:title "create-comment"}
[:thread-id ::sm/uuid]
[:content :string]
[:content [:string {:max 250}]]
[:share-id {:optional true} [:maybe ::sm/uuid]]])
(sv/defmethod ::create-comment
@@ -432,12 +442,11 @@
{:keys [team-id project-id page-name] :as file} (get-file cfg file-id page-id)]
(files/check-comment-permissions! conn profile-id file-id share-id)
(quotes/check-quote! conn
{::quotes/id ::quotes/comments-per-file
::quotes/profile-id profile-id
::quotes/team-id team-id
::quotes/project-id project-id
::quotes/file-id file-id})
(quotes/check! cfg {::quotes/id ::quotes/comments-per-file
::quotes/profile-id profile-id
::quotes/team-id team-id
::quotes/project-id project-id
::quotes/file-id file-id})
;; Update the page-name cached attribute on comment thread table.
(when (not= page-name (:page-name thread))
@@ -477,7 +486,7 @@
schema:update-comment
[:map {:title "update-comment"}
[:id ::sm/uuid]
[:content :string]
[:content [:string {:max 250}]]
[:share-id {:optional true} [:maybe ::sm/uuid]]])
(sv/defmethod ::update-comment

View File

@@ -18,10 +18,7 @@
[app.util.services :as sv]
[app.util.time :as dt]
[buddy.core.codecs :as bc]
[buddy.core.nonce :as bn]
[clojure.spec.alpha :as s]))
(s/def ::create-demo-profile any?)
[buddy.core.nonce :as bn]))
(sv/defmethod ::create-demo-profile
"A command that is responsible of creating a demo purpose
@@ -48,7 +45,7 @@
params {:email email
:fullname fullname
:is-active true
:deleted-at (dt/in-future cf/deletion-delay)
:deleted-at (dt/in-future (cf/get-deletion-delay))
:password (profile/derive-password cfg password)
:props {}}]

Some files were not shown because too many files have changed in this diff Show More