mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
Merge remote-tracking branch 'origin/staging' into develop
Some checks failed
_DEVELOP / build-bundle (push) Has been cancelled
_DEVELOP / build-docker (push) Has been cancelled
_STAGING / build-bundle (push) Has been cancelled
_STAGING / build-docker (push) Has been cancelled
Commit Message Check / Check Commit Message (push) Has been cancelled
Some checks failed
_DEVELOP / build-bundle (push) Has been cancelled
_DEVELOP / build-docker (push) Has been cancelled
_STAGING / build-bundle (push) Has been cancelled
_STAGING / build-docker (push) Has been cancelled
Commit Message Check / Check Commit Message (push) Has been cancelled
This commit is contained in:
@@ -57,6 +57,7 @@
|
|||||||
- Alternative ways of creating variants - Button Viewport [Taiga #11931](https://tree.taiga.io/project/penpot/us/11931)
|
- Alternative ways of creating variants - Button Viewport [Taiga #11931](https://tree.taiga.io/project/penpot/us/11931)
|
||||||
- Reorder properties for a component [Taiga #10225](https://tree.taiga.io/project/penpot/us/10225)
|
- Reorder properties for a component [Taiga #10225](https://tree.taiga.io/project/penpot/us/10225)
|
||||||
- File Data storage layout refactor [Github #7345](https://github.com/penpot/penpot/pull/7345)
|
- File Data storage layout refactor [Github #7345](https://github.com/penpot/penpot/pull/7345)
|
||||||
|
- Make several queries optimization on comment threads [Github #7506](https://github.com/penpot/penpot/pull/7506)
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
@@ -71,6 +72,9 @@
|
|||||||
- Fix auto-width changes to fixed when switching variants [Taiga #12172](https://tree.taiga.io/project/penpot/issue/12172)
|
- Fix auto-width changes to fixed when switching variants [Taiga #12172](https://tree.taiga.io/project/penpot/issue/12172)
|
||||||
- Fix component number has no singular translation string [Taiga #12106](https://tree.taiga.io/project/penpot/issue/12106)
|
- Fix component number has no singular translation string [Taiga #12106](https://tree.taiga.io/project/penpot/issue/12106)
|
||||||
- Fix adding/removing identical text fills [Taiga #12287](https://tree.taiga.io/project/penpot/issue/12287)
|
- Fix adding/removing identical text fills [Taiga #12287](https://tree.taiga.io/project/penpot/issue/12287)
|
||||||
|
- Fix scroll on the inspect tab [Taiga #12293](https://tree.taiga.io/project/penpot/issue/12293)
|
||||||
|
- Fix lock proportion tooltip [Taiga #12326](https://tree.taiga.io/project/penpot/issue/12326)
|
||||||
|
- Fix internal Error when selecting a set by name in the token theme editor [Taiga #12310](https://tree.taiga.io/project/penpot/issue/12310)
|
||||||
|
|
||||||
|
|
||||||
## 2.10.1
|
## 2.10.1
|
||||||
|
|||||||
@@ -234,36 +234,39 @@
|
|||||||
(files/check-comment-permissions! conn profile-id file-id share-id)
|
(files/check-comment-permissions! conn profile-id file-id share-id)
|
||||||
(get-comment-threads conn profile-id file-id))))
|
(get-comment-threads conn profile-id file-id))))
|
||||||
|
|
||||||
(def ^:private sql:comment-threads
|
(defn- get-comment-threads-sql
|
||||||
"SELECT DISTINCT ON (ct.id)
|
[where]
|
||||||
ct.*,
|
(str/ffmt
|
||||||
pf.fullname AS owner_fullname,
|
"SELECT DISTINCT ON (ct.id)
|
||||||
pf.email AS owner_email,
|
ct.*,
|
||||||
pf.photo_id AS owner_photo_id,
|
pf.fullname AS owner_fullname,
|
||||||
p.team_id AS team_id,
|
pf.email AS owner_email,
|
||||||
f.name AS file_name,
|
pf.photo_id AS owner_photo_id,
|
||||||
f.project_id AS project_id,
|
p.team_id AS team_id,
|
||||||
first_value(c.content) OVER w AS content,
|
f.name AS file_name,
|
||||||
(SELECT count(1)
|
f.project_id AS project_id,
|
||||||
FROM comment AS c
|
first_value(c.content) OVER w AS content,
|
||||||
WHERE c.thread_id = ct.id) AS count_comments,
|
(SELECT count(1)
|
||||||
(SELECT count(1)
|
FROM comment AS c
|
||||||
FROM comment AS c
|
WHERE c.thread_id = ct.id) AS count_comments,
|
||||||
WHERE c.thread_id = ct.id
|
(SELECT count(1)
|
||||||
AND c.created_at >= coalesce(cts.modified_at, ct.created_at)) AS count_unread_comments
|
FROM comment AS c
|
||||||
FROM comment_thread AS ct
|
WHERE c.thread_id = ct.id
|
||||||
INNER JOIN comment AS c ON (c.thread_id = ct.id)
|
AND c.created_at >= coalesce(cts.modified_at, ct.created_at)) AS count_unread_comments
|
||||||
INNER JOIN file AS f ON (f.id = ct.file_id)
|
FROM comment_thread AS ct
|
||||||
INNER JOIN project AS p ON (p.id = f.project_id)
|
INNER JOIN comment AS c ON (c.thread_id = ct.id)
|
||||||
LEFT JOIN comment_thread_status AS cts ON (cts.thread_id = ct.id AND cts.profile_id = ?)
|
INNER JOIN file AS f ON (f.id = ct.file_id)
|
||||||
LEFT JOIN profile AS pf ON (ct.owner_id = pf.id)
|
INNER JOIN project AS p ON (p.id = f.project_id)
|
||||||
WHERE f.deleted_at IS NULL
|
LEFT JOIN comment_thread_status AS cts ON (cts.thread_id = ct.id AND cts.profile_id = ?)
|
||||||
AND p.deleted_at IS NULL
|
LEFT JOIN profile AS pf ON (ct.owner_id = pf.id)
|
||||||
WINDOW w AS (PARTITION BY c.thread_id ORDER BY c.created_at ASC)")
|
WHERE f.deleted_at IS NULL
|
||||||
|
AND p.deleted_at IS NULL
|
||||||
|
%1
|
||||||
|
WINDOW w AS (PARTITION BY c.thread_id ORDER BY c.created_at ASC)"
|
||||||
|
where))
|
||||||
|
|
||||||
(def ^:private sql:comment-threads-by-file-id
|
(def ^:private sql:comment-threads-by-file-id
|
||||||
(str "WITH threads AS (" sql:comment-threads ")"
|
(get-comment-threads-sql "AND ct.file_id = ?"))
|
||||||
"SELECT * FROM threads WHERE file_id = ?"))
|
|
||||||
|
|
||||||
(defn- get-comment-threads
|
(defn- get-comment-threads
|
||||||
[conn profile-id file-id]
|
[conn profile-id file-id]
|
||||||
@@ -273,34 +276,28 @@
|
|||||||
;; --- COMMAND: Get Unread Comment Threads
|
;; --- COMMAND: Get Unread Comment Threads
|
||||||
|
|
||||||
(def ^:private sql:unread-all-comment-threads-by-team
|
(def ^:private sql:unread-all-comment-threads-by-team
|
||||||
(str "WITH threads AS (" sql:comment-threads ")"
|
(str "WITH threads AS ("
|
||||||
"SELECT * FROM threads WHERE count_unread_comments > 0 AND team_id = ?"))
|
(get-comment-threads-sql "AND p.team_id = ?")
|
||||||
|
")"
|
||||||
|
"SELECT t.* FROM threads AS t
|
||||||
|
WHERE t.count_unread_comments > 0"))
|
||||||
|
|
||||||
;; The partial configuration will retrieve only comments created by the user and
|
|
||||||
;; threads that have a mention to the user.
|
|
||||||
(def ^:private sql:unread-partial-comment-threads-by-team
|
(def ^:private sql:unread-partial-comment-threads-by-team
|
||||||
(str "WITH threads AS (" sql:comment-threads ")"
|
(str "WITH threads AS ("
|
||||||
"SELECT * FROM threads
|
(get-comment-threads-sql "AND p.team_id = ? AND (ct.owner_id = ? OR ? = ANY(ct.mentions))")
|
||||||
WHERE count_unread_comments > 0
|
")"
|
||||||
AND team_id = ?
|
"SELECT t.* FROM threads AS t
|
||||||
AND (owner_id = ? OR ? = ANY(mentions))"))
|
WHERE t.count_unread_comments > 0"))
|
||||||
|
|
||||||
(defn- get-unread-comment-threads
|
(defn- get-unread-comment-threads
|
||||||
[cfg profile-id team-id]
|
[cfg profile-id team-id]
|
||||||
(let [profile (-> (db/get cfg :profile {:id profile-id})
|
(let [profile (-> (db/get cfg :profile {:id profile-id})
|
||||||
(profile/decode-row))
|
(profile/decode-row))
|
||||||
notify (or (-> profile :props :notifications :dashboard-comments) :all)]
|
notify (or (-> profile :props :notifications :dashboard-comments) :all)
|
||||||
|
result (case notify
|
||||||
(case notify
|
:all (db/exec! cfg [sql:unread-all-comment-threads-by-team profile-id team-id])
|
||||||
:all
|
:partial (db/exec! cfg [sql:unread-partial-comment-threads-by-team profile-id team-id profile-id profile-id]))]
|
||||||
(->> (db/exec! cfg [sql:unread-all-comment-threads-by-team profile-id team-id])
|
(into [] xf-decode-row result)))
|
||||||
(into [] xf-decode-row))
|
|
||||||
|
|
||||||
:partial
|
|
||||||
(->> (db/exec! cfg [sql:unread-partial-comment-threads-by-team profile-id team-id profile-id profile-id])
|
|
||||||
(into [] xf-decode-row))
|
|
||||||
|
|
||||||
[])))
|
|
||||||
|
|
||||||
(def ^:private
|
(def ^:private
|
||||||
schema:get-unread-comment-threads
|
schema:get-unread-comment-threads
|
||||||
@@ -323,16 +320,17 @@
|
|||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
[:share-id {:optional true} [:maybe ::sm/uuid]]])
|
[:share-id {:optional true} [:maybe ::sm/uuid]]])
|
||||||
|
|
||||||
|
(def ^:private sql:get-comment-thread
|
||||||
|
(get-comment-threads-sql "AND ct.file_id = ? AND ct.id = ?"))
|
||||||
|
|
||||||
(sv/defmethod ::get-comment-thread
|
(sv/defmethod ::get-comment-thread
|
||||||
{::doc/added "1.15"
|
{::doc/added "1.15"
|
||||||
::sm/params schema:get-comment-thread}
|
::sm/params schema:get-comment-thread}
|
||||||
[cfg {:keys [::rpc/profile-id file-id id share-id] :as params}]
|
[cfg {:keys [::rpc/profile-id file-id id share-id] :as params}]
|
||||||
(db/run! cfg (fn [{:keys [::db/conn]}]
|
(db/run! cfg (fn [{:keys [::db/conn]}]
|
||||||
(files/check-comment-permissions! conn profile-id file-id share-id)
|
(files/check-comment-permissions! conn profile-id file-id share-id)
|
||||||
(let [sql (str "WITH threads AS (" sql:comment-threads ")"
|
(some-> (db/exec-one! conn [sql:get-comment-thread profile-id file-id id])
|
||||||
"SELECT * FROM threads WHERE id = ? AND file_id = ?")]
|
(decode-row)))))
|
||||||
(-> (db/exec-one! conn [sql profile-id id file-id])
|
|
||||||
(decode-row))))))
|
|
||||||
|
|
||||||
;; --- COMMAND: Retrieve Comments
|
;; --- COMMAND: Retrieve Comments
|
||||||
|
|
||||||
|
|||||||
@@ -864,6 +864,12 @@ test.describe("Tokens: Themes modal", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const firstButton = await tokenThemeUpdateCreateModal
|
||||||
|
.getByTestId('tokens-set-item')
|
||||||
|
.first();
|
||||||
|
|
||||||
|
await firstButton.click();
|
||||||
|
|
||||||
await tokenThemeUpdateCreateModal
|
await tokenThemeUpdateCreateModal
|
||||||
.getByRole("button", {
|
.getByRole("button", {
|
||||||
name: "Save theme",
|
name: "Save theme",
|
||||||
|
|||||||
@@ -20,13 +20,15 @@
|
|||||||
[:icon
|
[:icon
|
||||||
[:and :string [:fn #(contains? icon-list %)]]]
|
[:and :string [:fn #(contains? icon-list %)]]]
|
||||||
[:aria-label :string]
|
[:aria-label :string]
|
||||||
|
[:tooltip-placement {:optional true}
|
||||||
|
[:maybe [:enum "top" "bottom" "left" "right" "top-right" "bottom-right" "bottom-left" "top-left"]]]
|
||||||
[:variant {:optional true}
|
[:variant {:optional true}
|
||||||
[:maybe [:enum "primary" "secondary" "ghost" "destructive" "action"]]]])
|
[:maybe [:enum "primary" "secondary" "ghost" "destructive" "action"]]]])
|
||||||
|
|
||||||
(mf/defc icon-button*
|
(mf/defc icon-button*
|
||||||
{::mf/schema schema:icon-button
|
{::mf/schema schema:icon-button
|
||||||
::mf/memo true}
|
::mf/memo true}
|
||||||
[{:keys [class icon icon-class variant aria-label children] :rest props}]
|
[{:keys [class icon icon-class variant aria-label children tooltip-placement] :rest props}]
|
||||||
(let [variant
|
(let [variant
|
||||||
(d/nilv variant "primary")
|
(d/nilv variant "primary")
|
||||||
|
|
||||||
@@ -47,6 +49,7 @@
|
|||||||
:aria-labelledby tooltip-id})]
|
:aria-labelledby tooltip-id})]
|
||||||
|
|
||||||
[:> tooltip* {:content aria-label
|
[:> tooltip* {:content aria-label
|
||||||
|
:placement tooltip-placement
|
||||||
:id tooltip-id}
|
:id tooltip-id}
|
||||||
[:> :button props
|
[:> :button props
|
||||||
[:> icon* {:icon-id icon :aria-hidden true :class icon-class}]
|
[:> icon* {:icon-id icon :aria-hidden true :class icon-class}]
|
||||||
|
|||||||
@@ -146,9 +146,12 @@
|
|||||||
.viewer-tab-switcher {
|
.viewer-tab-switcher {
|
||||||
--tabs-nav-padding-inline-start: 0;
|
--tabs-nav-padding-inline-start: 0;
|
||||||
--tabs-nav-padding-inline-end: var(--sp-m);
|
--tabs-nav-padding-inline-end: var(--sp-m);
|
||||||
--max-inspect-tab-height: calc(100vh - 12rem);
|
|
||||||
|
|
||||||
|
/* same height as .element-options in workspace/sidebar/options.scss */
|
||||||
|
/* which is one of the parents of this component */
|
||||||
|
--max-inspect-tab-height: var(--sidebar-element-options-height);
|
||||||
max-block-size: var(--max-inspect-tab-height);
|
max-block-size: var(--max-inspect-tab-height);
|
||||||
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,10 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: deprecated.$s-8;
|
gap: deprecated.$s-8;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100vh - $sz-88);
|
/* FIXME: This is hacky and prone to break, we should tackle the whole layout
|
||||||
|
of the sidebar differently */
|
||||||
|
--sidebar-element-options-height: calc(100vh - $sz-88);
|
||||||
|
height: var(--sidebar-element-options-height);
|
||||||
padding-top: deprecated.$s-8;
|
padding-top: deprecated.$s-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
:value (:height values)}]]])
|
:value (:height values)}]]])
|
||||||
|
|
||||||
[:> icon-button* {:variant "ghost"
|
[:> icon-button* {:variant "ghost"
|
||||||
|
:tooltip-placement "top-left"
|
||||||
:icon (if proportion-lock "lock" "unlock")
|
:icon (if proportion-lock "lock" "unlock")
|
||||||
:class (stl/css-case :selected (true? proportion-lock))
|
:class (stl/css-case :selected (true? proportion-lock))
|
||||||
:disabled (= proportion-lock :multiple)
|
:disabled (= proportion-lock :multiple)
|
||||||
|
|||||||
@@ -319,7 +319,8 @@
|
|||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps on-toggle-token-set)
|
(mf/deps on-toggle-token-set)
|
||||||
(fn [set-id]
|
(fn [set-id]
|
||||||
(on-toggle-token-set set-id)))]
|
(let [set (ctob/get-set lib set-id)]
|
||||||
|
(on-toggle-token-set (ctob/get-name set)))))]
|
||||||
|
|
||||||
[:div {:class (stl/css :themes-modal-wrapper)}
|
[:div {:class (stl/css :themes-modal-wrapper)}
|
||||||
[:> heading* {:level 2 :typography "headline-medium" :class (stl/css :themes-modal-title)}
|
[:> heading* {:level 2 :typography "headline-medium" :class (stl/css :themes-modal-title)}
|
||||||
|
|||||||
Reference in New Issue
Block a user