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

This commit is contained in:
Andrey Antukh 2026-08-31 11:52:26 +02:00
commit 292390f0eb
30 changed files with 78 additions and 54 deletions

View File

@ -40,10 +40,27 @@ Skipping this step is the #1 cause of incorrect or incomplete work.
`github.com/penpot/penpot/security/advisories/GHSA-*`, extract the GHSA ID
from the URL and run `python3 scripts/gh.py advisories <GHSA-ID>` to fetch
full advisory details before proceeding.
- **Issue or PR mentioned** — When the user mentions a penpot/penpot issue or
PR (URL like `github.com/penpot/penpot/issues/<n>` / `.../pull/<n>`, or a
bare `#<n>` when context clearly refers to this repo), fetch details via CLI
instead of WebFetch:
- Issue → `gh issue view <n> --repo penpot/penpot` (add `--comments` when
discussion context matters).
- Single PR → `gh pr view <n> --repo penpot/penpot`.
- Multiple PRs (list, file, or milestone) → `python3 scripts/gh.py prs ...`.
Do this before proceeding. Only use WebFetch if the CLI fails.
## Writing Rules
Use the `ste` skill when the user explicitly requests STE, `/ste`, or ASD-STE100.
Writing rules, from Orwell, 1946. These govern prose: docs, PR text, messages. Never touch code or technical terms; swap in everyday words only where precision survives.
1. Never use a metaphor, simile or other figure of speech which you are used to seeing in print.
2. Never use a long word where a short one will do.
3. If it is possible to cut a word out, always cut it out.
4. Never use the passive where you can use the active.
5. Never use a foreign phrase, a scientific word or a jargon word if you can think of an everyday English equivalent.
6. Break any of these rules sooner than say anything outright barbarous.
Review every prose output against these rules before delivering.
---

View File

@ -191,7 +191,7 @@
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.
Since this file is in your Personal Projects, 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>

View File

@ -2,7 +2,7 @@ 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.
Since this file is in your Personal Projects, 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:

View File

@ -191,7 +191,7 @@
“{{file-name|abbreviate:25}}”.
</p>
<p>
Please note that the file is currently in Your Penpot 's team, so direct access cannot be
Please note that the file is currently in Personal Projects, so direct access cannot be
granted. However, you have two options to provide the requested access:
</p>
<ul>

View File

@ -5,7 +5,7 @@ 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:
Please note that the file is currently in Personal Projects, so direct access cannot be granted. However, you have two options to provide the requested access:
- Move the File to Another Team:

View File

@ -505,13 +505,13 @@
:schema schema:request-file-access))
(def request-file-access-yourpenpot
"File access on Your Penpot request email."
"File access on Personal Projects 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."
"File access on Personal Projects view mode request email."
(template-factory
:id ::request-file-access-yourpenpot-view
:schema schema:request-file-access))

View File

@ -209,7 +209,7 @@
[:enum
"customer_service"
"low_quality"
"missing_feature"
"missing_features"
"other"
"switched_service"
"too_complex"

View File

@ -245,7 +245,7 @@
[:enum
"customer_service"
"low_quality"
"missing_feature"
"missing_features"
"other"
"switched_service"
"too_complex"

View File

@ -336,7 +336,7 @@
(doseq [{:keys [id reassign-to]} teams-to-leave]
(teams/leave-team cfg {:profile-id profile-id :id id :reassign-to reassign-to}))
;; Process organization "Your Penpot" team: keep with prefix if needed, otherwise delete.
;; Process organization "Personal Projects" team: keep with prefix if needed, otherwise delete.
(when default-team-id
(if keep-default-team?
(db/exec! conn [sql:prefix-team-name-and-unset-default organization-prefix default-team-id])

View File

@ -524,7 +524,7 @@
;; Penpot back through two paths: ::notify-user-organizations-deletion
;; (during delete-owned-organizations) and ::notify-organization-deletion.
;; Both preserve organization teams unchanged and only prefix or delete
;; imported "Your Penpot" teams according to whether they still have files.
;; imported "Personal Projects" teams according to whether they still have files.
;; Let Nitrate clean up the data associated with the deleted Penpot user:
;; owned organizations, remaining memberships, and subscription cancellation.
(when (contains? cf/flags :admin-console)

View File

@ -575,7 +575,7 @@
(set/difference cfeat/frontend-only-features)
(set/difference cfeat/no-team-inheritable-features))
params {:profile-id profile-id
:name "Your Penpot"
:name "Personal Projects"
:features features
:organization-id organization-id
:is-default true}
@ -829,7 +829,7 @@
:code :only-owner-can-delete-team))
;; Protect the user's personal default team from deletion.
;; Organization-scoped default teams ("Your Penpot") are allowed to be deleted when they have no files.
;; Organization-scoped default teams ("Personal Projects") are allowed to be deleted when they have no files.
(when (and (:is-default team) (not in-organization?))
(ex/raise :type :validation
:code :non-deletable-team

View File

@ -318,7 +318,7 @@ RETURNING id, deleted_at;")
(defn manage-deleted-organization-teams
"For a deleted organization, preserve organization teams unchanged and only prefix or
delete member Your Penpot teams depending on whether they still contain files."
delete member Personal Projects teams depending on whether they still contain files."
[cfg {:keys [organization-id organization-name teams]}]
(let [all-team-ids (->> teams
(map :id)
@ -347,13 +347,13 @@ RETURNING id, deleted_at;")
teams-to-delete (->> your-penpot-team-ids (remove teams-with-files) (into []))]
;; Organization teams move to the fallback organization unchanged. Only imported
;; Your Penpot teams keep the organization prefix when they still have files.
;; Personal Projects teams keep the organization prefix when they still have files.
(when (seq teams-to-prefix)
(db/exec! conn [sql:prefix-teams-name-and-unset-default
organization-prefix
(db/create-array conn "uuid" teams-to-prefix)]))
;; Empty imported Your Penpot teams disappear entirely.
;; Empty imported Personal Projects teams disappear entirely.
(soft-delete-teams! cfg teams-to-delete)
(notifications/notify-organization-deletion cfg organization-id organization-name all-team-ids teams-to-delete)
@ -362,7 +362,7 @@ RETURNING id, deleted_at;")
(sv/defmethod ::notify-organization-deletion
"For a deleted organization, preserve organization teams and only prefix or delete
imported Your Penpot teams before notifying connected users."
imported Personal Projects before notifying connected users."
{::doc/added "2.18"
::sm/params schema:notify-organization-deletion
::rpc/auth false}
@ -382,7 +382,7 @@ RETURNING id, deleted_at;")
(sv/defmethod ::notify-user-organizations-deletion
"For a given user, find all owned organizations and apply the deleted-organization
transfer rules to their imported Your Penpot teams."
transfer rules to their imported Personal Projects teams."
{::doc/added "2.18"
::sm/params schema:notify-user-organizations-deletion
::nitrate/sso false}

View File

@ -232,7 +232,7 @@
[:enum
"customer_service"
"low_quality"
"missing_feature"
"missing_features"
"other"
"switched_service"
"too_complex"

View File

@ -268,7 +268,7 @@
new-team (th/db-get :team {:id new-team-id})]
(t/is (th/success? out))
(t/is (= 1 (count (set/difference after-teams before-teams))))
(t/is (= "Your Penpot" (:name new-team)))
(t/is (= "Personal Projects" (:name new-team)))
(t/is (true? (:is-default new-team))))))
(t/deftest get-managed-profiles-returns-unique-members-for-owned-teams

View File

@ -100,7 +100,7 @@ RUN set -eux; \
FROM base AS setup-opencode
ENV OPENCODE_VERSION=1.18.21
ENV OPENCODE_VERSION=1.18.25
RUN set -ex; \
ARCH="$(dpkg --print-architecture)"; \

View File

@ -86,7 +86,7 @@ export class DashboardPage extends BaseWebSocketPage {
this.searchInput = page.getByPlaceholder("Search…");
this.teamDropdown = this.sidebar.getByRole("button", {
name: "Your Penpot",
name: "Personal Projects",
});
this.userAccount = this.sidebar.getByRole("button", {
name: /Princesa Leia/,

View File

@ -7,7 +7,7 @@ export class OnboardingPage extends BaseWebSocketPage {
}
async fillOnboardingInputsStep1() {
await this.page.getByText("Personal").click();
await this.page.getByText("Personal", { exact: true }).click();
await this.page.getByText("Select option").click();
await this.page.getByText("Product Management").click();

View File

@ -43,15 +43,25 @@
(swap! storage/storage dissoc
nitrate-entry-pending-popup-key)))
(def ^:private offline-connectivity
{:licenses false})
(defn- air-gapped?
[]
(contains? cf/flags :air-gapped-conf))
(defn show-nitrate-popup
([popup-type] (show-nitrate-popup popup-type {}))
([popup-type extra-props]
(ptk/reify ::show-nitrate-popup
ptk/WatchEvent
(watch [_ _ _]
(->> (rp/cmd! ::get-nitrate-connectivity {})
(rx/map (fn [connectivity]
(modal/show popup-type (merge (or connectivity {}) extra-props)))))))))
(if (air-gapped?)
(rx/of (modal/show popup-type (merge offline-connectivity extra-props)))
(->> (rp/cmd! ::get-nitrate-connectivity {})
(rx/map (fn [connectivity]
(modal/show popup-type
(merge (or connectivity {}) extra-props))))))))))
(defn build-admin-console-url
([path]

View File

@ -37,7 +37,7 @@
(defn- get-team-name
[team]
(if (:is-default team)
(tr "dashboard.your-penpot")
(tr "dashboard.personal-projects")
(:name team)))
(defn- group-by-team

View File

@ -43,7 +43,7 @@
(mf/with-effect [team]
(when team
(let [tname (if (:is-default team)
(tr "dashboard.your-penpot")
(tr "dashboard.personal-projects")
(:name team))]
(case section
:fonts (dom/set-html-title (tr "title.dashboard.fonts" tname))

View File

@ -52,7 +52,7 @@
(mf/with-effect [team]
(let [tname (if (:is-default team)
(tr "dashboard.your-penpot")
(tr "dashboard.personal-projects")
(:name team))]
(dom/set-html-title (tr "title.dashboard.shared-libraries" tname))))

View File

@ -357,7 +357,7 @@
(mf/with-effect [team]
(let [tname (if (:is-default team)
(tr "dashboard.your-penpot")
(tr "dashboard.personal-projects")
(:name team))]
(dom/set-html-title (tr "title.dashboard.projects" tname))))

View File

@ -44,7 +44,7 @@
(mf/with-effect [team]
(when team
(let [tname (if (:is-default team)
(tr "dashboard.your-penpot")
(tr "dashboard.personal-projects")
(:name team))]
(dom/set-html-title (tr "title.dashboard.search" tname)))))

View File

@ -438,7 +438,7 @@
(when-not (contains? cf/flags :admin-console)
[:span {:class (stl/css :penpot-icon)} deprecated-icon/logo-icon])
[:span {:class (stl/css :team-text)} (if (contains? cf/flags :admin-console) (tr "dashboard.personal-projects") (tr "dashboard.your-penpot"))]
[:span {:class (stl/css :team-text)} (tr "dashboard.personal-projects")]
(when (= default-team-id (:id team))
tick-icon)]
@ -725,7 +725,7 @@
current-organization (dtm/team->organization team)
;; Find the "your-penpot" teams, and transform them in organizations. When
;; Find the "personal-projects" teams, and transform them in organizations. When
;; the selected team is directly accessible but not listed in
;; membership teams, include only its organization so the organization selector can
;; show the current selection without leaking the team into the
@ -972,7 +972,7 @@
:team-name-no-logo nitrate?)}
(when-not nitrate?
[:span {:class (stl/css :penpot-icon)} deprecated-icon/logo-icon])
[:span {:class (stl/css :team-text)} (if nitrate? (tr "dashboard.personal-projects") (tr "dashboard.default-team-name"))]]
[:span {:class (stl/css :team-text)} (tr "dashboard.personal-projects")]]
(and (contains? cf/flags :subscriptions)
(not is-default?)

View File

@ -644,7 +644,7 @@
(dom/set-html-title
(tr "title.team-members"
(if (:is-default team)
(tr "dashboard.your-penpot")
(tr "dashboard.personal-projects")
(:name team)))))
(mf/with-effect [(:id team)]
@ -1248,7 +1248,7 @@
(dom/set-html-title
(tr "title.team-invitations"
(if (:is-default team)
(tr "dashboard.your-penpot")
(tr "dashboard.personal-projects")
(:name team)))))
(mf/with-effect [(:id team)]
@ -1528,7 +1528,7 @@
(dom/set-html-title
(tr "title.team-webhooks"
(if (:is-default team)
(tr "dashboard.your-penpot")
(tr "dashboard.personal-projects")
(:name team)))))
(mf/with-effect []
@ -1635,7 +1635,7 @@
(mf/with-effect [team]
(dom/set-html-title (tr "title.team-settings"
(if (:is-default team)
(tr "dashboard.your-penpot")
(tr "dashboard.personal-projects")
(:name team)))))
(mf/with-effect []

View File

@ -839,7 +839,8 @@
(mf/with-effect [handle-unmount] handle-unmount)
[:div {:class [class (stl/css-case :input-wrapper true
:resizable (not is-token-applied?))]
:resizable (and (not is-token-applied?)
(not disabled)))]
:ref wrapper-ref
:on-pointer-down on-scrub-pointer-down
:on-pointer-move on-scrub-pointer-move

View File

@ -22,9 +22,10 @@
column-gap: var(--sp-xs);
align-items: center;
inline-size: 100%;
block-size: var(--token-field-height);
background: var(--token-field-bg-color);
border-radius: $br-8;
padding-inline-end: var(--sp-xs);
padding: 0 var(--input-padding-size, var(--sp-s));
outline: $b-1 solid var(--token-field-outline-color);
position: relative;

View File

@ -344,7 +344,7 @@
(mf/defc view-menu*
{::mf/private true
::mf/wrap [mf/memo]}
[{:keys [layout toggle-flag on-close]}]
[{:keys [layout toggle-flag on-close on-close-all]}]
(let [read-only? (mf/use-ctx ctx/workspace-read-only?)
toggle-color-palette
@ -365,11 +365,11 @@
toggle-comments-visibility
(mf/use-fn
(mf/deps on-close)
(mf/deps on-close-all)
(fn [event]
(dom/stop-propagation event)
(st/emit! (dwcm/toggle-comments-visibility {:origin "workspace:menu"}))
(on-close)))]
(on-close-all)))]
[:> dropdown-menu* {:show true
:class (stl/css :base-menu :sub-menu :pos-3)
@ -1139,7 +1139,8 @@
:view
[:> view-menu* {:layout layout
:toggle-flag toggle-flag
:on-close close-sub-menu}]
:on-close close-sub-menu
:on-close-all close-all-menus}]
:preferences
[:> preferences-menu* {:layout layout

View File

@ -413,7 +413,7 @@ msgstr "Pin this version"
#: src/app/main/ui/components/context_menu_a11y.cljs:300, src/app/main/ui/dashboard/sidebar.cljs:882
msgid "dashboard.default-team-name"
msgstr "Your Penpot"
msgstr "Personal Projects"
#: src/app/main/ui/dashboard/deleted.cljs:265
msgid "dashboard.delete-all-forever-confirmation.description"
@ -1466,9 +1466,6 @@ msgid "dashboard.your-name"
msgstr "Your name"
#: src/app/main/ui/dashboard/file_menu.cljs:40, src/app/main/ui/dashboard/fonts.cljs:46, src/app/main/ui/dashboard/libraries.cljs:55, src/app/main/ui/dashboard/projects.cljs:352, src/app/main/ui/dashboard/search.cljs:47, src/app/main/ui/dashboard/sidebar.cljs:411, src/app/main/ui/dashboard/team.cljs:616, src/app/main/ui/dashboard/team.cljs:1191, src/app/main/ui/dashboard/team.cljs:1471, src/app/main/ui/dashboard/team.cljs:1577
msgid "dashboard.your-penpot"
msgstr "Your Penpot"
msgid "dashboard.personal-projects"
msgstr "Personal Projects"
@ -4696,7 +4693,7 @@ msgstr "You don't have access to this file."
#: src/app/main/ui/static.cljs:62, src/app/main/ui/static.cljs:265, src/app/main/ui/static.cljs:271, src/app/main/ui/static.cljs:277, src/app/main/ui/static.cljs:283, src/app/main/ui/static.cljs:292, src/app/main/ui/static.cljs:301
msgid "not-found.no-permission.go-dashboard"
msgstr "Go to your Penpot"
msgstr "Go to Personal Projects"
#: src/app/main/ui/static.cljs:289, src/app/main/ui/static.cljs:298
msgid "not-found.no-permission.if-approves"

View File

@ -420,7 +420,7 @@ msgstr "Guardar esta versión"
#: src/app/main/ui/components/context_menu_a11y.cljs:300, src/app/main/ui/dashboard/sidebar.cljs:882
msgid "dashboard.default-team-name"
msgstr "Tu Penpot"
msgstr "Proyectos Personales"
#: src/app/main/ui/dashboard/deleted.cljs:265
msgid "dashboard.delete-all-forever-confirmation.description"
@ -1473,9 +1473,6 @@ msgid "dashboard.your-name"
msgstr "Tu nombre"
#: src/app/main/ui/dashboard/file_menu.cljs:40, src/app/main/ui/dashboard/fonts.cljs:46, src/app/main/ui/dashboard/libraries.cljs:55, src/app/main/ui/dashboard/projects.cljs:352, src/app/main/ui/dashboard/search.cljs:47, src/app/main/ui/dashboard/sidebar.cljs:411, src/app/main/ui/dashboard/team.cljs:616, src/app/main/ui/dashboard/team.cljs:1191, src/app/main/ui/dashboard/team.cljs:1471, src/app/main/ui/dashboard/team.cljs:1577
msgid "dashboard.your-penpot"
msgstr "Tu Penpot"
msgid "dashboard.personal-projects"
msgstr "Proyectos Personales"
@ -4569,7 +4566,7 @@ msgstr "No tienes permiso para acceder a este archivo."
#: src/app/main/ui/static.cljs:62, src/app/main/ui/static.cljs:265, src/app/main/ui/static.cljs:271, src/app/main/ui/static.cljs:277, src/app/main/ui/static.cljs:283, src/app/main/ui/static.cljs:292, src/app/main/ui/static.cljs:301
msgid "not-found.no-permission.go-dashboard"
msgstr "Ir a tu Penpot"
msgstr "Ir a tus Proyectos Personales"
#: src/app/main/ui/static.cljs:289, src/app/main/ui/static.cljs:298
msgid "not-found.no-permission.if-approves"