mirror of
https://github.com/penpot/penpot.git
synced 2026-09-14 07:59:36 +00:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
7f46c8c80e
@ -235,9 +235,8 @@
|
|||||||
:organization-name (:name organization)
|
:organization-name (:name organization)
|
||||||
:member-email (:email-to invitation)
|
:member-email (:email-to invitation)
|
||||||
:member-id (:id member)
|
:member-id (:id member)
|
||||||
:role role}
|
:role role
|
||||||
organization
|
:user-who-send-invitation (str profile-id)}
|
||||||
(assoc :user-who-send-invitation (str profile-id))
|
|
||||||
|
|
||||||
(not organization)
|
(not organization)
|
||||||
(assoc :team-belongs-to-organization (boolean team-organization-id)
|
(assoc :team-belongs-to-organization (boolean team-organization-id)
|
||||||
|
|||||||
@ -308,7 +308,9 @@
|
|||||||
(assoc :name "accept-organization-invitation")
|
(assoc :name "accept-organization-invitation")
|
||||||
(assoc :props
|
(assoc :props
|
||||||
(-> props
|
(-> props
|
||||||
(assoc :organization-id organization-id-on-add)
|
(assoc :organization-id organization-id-on-add
|
||||||
|
:user-id (:id profile)
|
||||||
|
:user-who-send-invitation (:created-by invitation))
|
||||||
(audit/clean-props))))))
|
(audit/clean-props))))))
|
||||||
|
|
||||||
(cond-> (assoc claims :state :created)
|
(cond-> (assoc claims :state :created)
|
||||||
@ -325,6 +327,8 @@
|
|||||||
(assoc :organization-id organization-id-on-add
|
(assoc :organization-id organization-id-on-add
|
||||||
:organization-member-add-source organization-add-source
|
:organization-member-add-source organization-add-source
|
||||||
:belongs-to-team-on-add (boolean team-id)
|
:belongs-to-team-on-add (boolean team-id)
|
||||||
|
:user-id (:id profile)
|
||||||
|
:user-who-send-invitation (:created-by invitation)
|
||||||
:organization-member-count-before
|
:organization-member-count-before
|
||||||
organization-member-count-before)
|
organization-member-count-before)
|
||||||
(audit/clean-props))}))))))
|
(audit/clean-props))}))))))
|
||||||
|
|||||||
@ -154,10 +154,14 @@
|
|||||||
(get-in % [:props :member-email])))
|
(get-in % [:props :member-email])))
|
||||||
events))]
|
events))]
|
||||||
(doseq [event [create-organization update-organization]]
|
(doseq [event [create-organization update-organization]]
|
||||||
|
(t/is (= (str (:id owner))
|
||||||
|
(get-in event [:props :user-who-send-invitation])))
|
||||||
(t/is (true? (get-in event [:props :team-belongs-to-organization])))
|
(t/is (true? (get-in event [:props :team-belongs-to-organization])))
|
||||||
(t/is (true? (get-in event [:props :adds-invitee-to-organization])))
|
(t/is (true? (get-in event [:props :adds-invitee-to-organization])))
|
||||||
(t/is (true? (get-in event [:props :invitee-already-organization-member]))))
|
(t/is (true? (get-in event [:props :invitee-already-organization-member]))))
|
||||||
|
|
||||||
|
(t/is (= (str (:id owner))
|
||||||
|
(get-in create-plain [:props :user-who-send-invitation])))
|
||||||
(t/is (false? (get-in create-plain [:props :team-belongs-to-organization])))
|
(t/is (false? (get-in create-plain [:props :team-belongs-to-organization])))
|
||||||
(t/is (false? (get-in create-plain [:props :adds-invitee-to-organization])))
|
(t/is (false? (get-in create-plain [:props :adds-invitee-to-organization])))
|
||||||
(t/is (false? (get-in create-plain [:props :invitee-already-organization-member])))))))
|
(t/is (false? (get-in create-plain [:props :invitee-already-organization-member])))))))
|
||||||
@ -521,6 +525,9 @@
|
|||||||
|
|
||||||
(let [event (organization-event)]
|
(let [event (organization-event)]
|
||||||
(t/is (= organization-id (get-in event [:props :organization-id])))
|
(t/is (= organization-id (get-in event [:props :organization-id])))
|
||||||
|
(t/is (= (:id invitee) (get-in event [:props :user-id])))
|
||||||
|
(t/is (= (:id inviter)
|
||||||
|
(get-in event [:props :user-who-send-invitation])))
|
||||||
(t/is (not (contains? (:props event) :organization-member-add-source)))
|
(t/is (not (contains? (:props event) :organization-member-add-source)))
|
||||||
(t/is (not (contains? (:props event) :belongs-to-team-on-add)))
|
(t/is (not (contains? (:props event) :belongs-to-team-on-add)))
|
||||||
(t/is (not (contains? (:props event) :organization-member-count-before)))
|
(t/is (not (contains? (:props event) :organization-member-count-before)))
|
||||||
@ -530,6 +537,10 @@
|
|||||||
(:origin @frontend-event)))
|
(:origin @frontend-event)))
|
||||||
(t/is (= organization-id
|
(t/is (= organization-id
|
||||||
(get-in @frontend-event [:props :organization-id])))
|
(get-in @frontend-event [:props :organization-id])))
|
||||||
|
(t/is (= (:id invitee)
|
||||||
|
(get-in @frontend-event [:props :user-id])))
|
||||||
|
(t/is (= (:id inviter)
|
||||||
|
(get-in @frontend-event [:props :user-who-send-invitation])))
|
||||||
(t/is (= "direct-organization-invitation"
|
(t/is (= "direct-organization-invitation"
|
||||||
(get-in @frontend-event [:props :organization-member-add-source])))
|
(get-in @frontend-event [:props :organization-member-add-source])))
|
||||||
(t/is (false? (get-in @frontend-event [:props :belongs-to-team-on-add])))
|
(t/is (false? (get-in @frontend-event [:props :belongs-to-team-on-add])))
|
||||||
@ -570,6 +581,9 @@
|
|||||||
(t/is (some #(= "accept-team-invitation-from" (:name %)) events))
|
(t/is (some #(= "accept-team-invitation-from" (:name %)) events))
|
||||||
(t/is (= (:id team) (get-in event [:props :team-id])))
|
(t/is (= (:id team) (get-in event [:props :team-id])))
|
||||||
(t/is (= organization-id (get-in event [:props :organization-id])))
|
(t/is (= organization-id (get-in event [:props :organization-id])))
|
||||||
|
(t/is (= (:id invitee) (get-in event [:props :user-id])))
|
||||||
|
(t/is (= (:id inviter)
|
||||||
|
(get-in event [:props :user-who-send-invitation])))
|
||||||
(t/is (not (contains? (:props event) :organization-member-add-source)))
|
(t/is (not (contains? (:props event) :organization-member-add-source)))
|
||||||
(t/is (not (contains? (:props event) :belongs-to-team-on-add)))
|
(t/is (not (contains? (:props event) :belongs-to-team-on-add)))
|
||||||
(t/is (not (contains? (:props event) :organization-member-count-before)))
|
(t/is (not (contains? (:props event) :organization-member-count-before)))
|
||||||
@ -578,6 +592,10 @@
|
|||||||
(t/is (= (:id team) (get-in @frontend-event [:props :team-id])))
|
(t/is (= (:id team) (get-in @frontend-event [:props :team-id])))
|
||||||
(t/is (= organization-id
|
(t/is (= organization-id
|
||||||
(get-in @frontend-event [:props :organization-id])))
|
(get-in @frontend-event [:props :organization-id])))
|
||||||
|
(t/is (= (:id invitee)
|
||||||
|
(get-in @frontend-event [:props :user-id])))
|
||||||
|
(t/is (= (:id inviter)
|
||||||
|
(get-in @frontend-event [:props :user-who-send-invitation])))
|
||||||
(t/is (= "team-invitation"
|
(t/is (= "team-invitation"
|
||||||
(get-in @frontend-event [:props :organization-member-add-source])))
|
(get-in @frontend-event [:props :organization-member-add-source])))
|
||||||
(t/is (true? (get-in @frontend-event [:props :belongs-to-team-on-add])))
|
(t/is (true? (get-in @frontend-event [:props :belongs-to-team-on-add])))
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
[promesa.core :as p]))
|
[promesa.core :as p]))
|
||||||
|
|
||||||
(defn render
|
(defn render
|
||||||
[{:keys [file-id page-id share-id token scale type objects skip-children is-wasm] :as params} on-object]
|
[{:keys [file-id page-id share-id token scale type objects skip-children] :as params} on-object]
|
||||||
(letfn [(prepare-options [uri]
|
(letfn [(prepare-options [uri]
|
||||||
#js {:screen #js {:width bw/default-viewport-width
|
#js {:screen #js {:width bw/default-viewport-width
|
||||||
:height bw/default-viewport-height}
|
:height bw/default-viewport-height}
|
||||||
@ -25,7 +25,7 @@
|
|||||||
:height bw/default-viewport-height}
|
:height bw/default-viewport-height}
|
||||||
:locale "en-US"
|
:locale "en-US"
|
||||||
:storageState #js {:cookies (bw/create-cookies uri {:token token})}
|
:storageState #js {:cookies (bw/create-cookies uri {:token token})}
|
||||||
:deviceScaleFactor (if is-wasm 1 scale) ;; wasm won't use deviceScaleFactor
|
:deviceScaleFactor scale
|
||||||
:userAgent bw/default-user-agent})
|
:userAgent bw/default-user-agent})
|
||||||
|
|
||||||
(render-object [page {:keys [id] :as object}]
|
(render-object [page {:keys [id] :as object}]
|
||||||
@ -59,9 +59,7 @@
|
|||||||
:share-id share-id
|
:share-id share-id
|
||||||
:object-id (mapv :id objects)
|
:object-id (mapv :id objects)
|
||||||
:route "objects"
|
:route "objects"
|
||||||
:skip-children skip-children
|
:skip-children skip-children}
|
||||||
:wasm (when is-wasm "true")
|
|
||||||
:scale scale}
|
|
||||||
uri (-> (cf/get-internal-uri)
|
uri (-> (cf/get-internal-uri)
|
||||||
(u/ensure-path-slash)
|
(u/ensure-path-slash)
|
||||||
(u/join "render.html")
|
(u/join "render.html")
|
||||||
|
|||||||
@ -600,6 +600,12 @@ export class WorkspacePage extends BaseWebSocketPage {
|
|||||||
.getByRole("button", { name: "Comments (C)" })
|
.getByRole("button", { name: "Comments (C)" })
|
||||||
.click(clickOptions);
|
.click(clickOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async toggleCommentsVisibilityFromMenu(clickOptions = {}) {
|
||||||
|
await this.page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await this.page.getByText("view").last().click();
|
||||||
|
await this.page.locator("#file-menu-comments").click(clickOptions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WorkspacePage;
|
export default WorkspacePage;
|
||||||
|
|||||||
@ -35,3 +35,64 @@ test("Group bubbles when zooming out if they overlap", async ({ page }) => {
|
|||||||
/unread/,
|
/unread/,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Opening the Comments section only temporarily overrides a disabled global comments setting", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const workspacePage = new WasmWorkspacePage(page);
|
||||||
|
await workspacePage.setupEmptyFile();
|
||||||
|
await workspacePage.setupFileWithComments();
|
||||||
|
await workspacePage.goToWorkspace();
|
||||||
|
|
||||||
|
const bubble = page.getByTestId("floating-thread-bubble-1");
|
||||||
|
|
||||||
|
// "Display comments" is enabled by default, so the bubble is already visible.
|
||||||
|
await expect(bubble).toBeVisible();
|
||||||
|
|
||||||
|
// Turn the global "Display comments" setting off from the main menu.
|
||||||
|
await workspacePage.toggleCommentsVisibilityFromMenu();
|
||||||
|
await expect(bubble).toBeHidden();
|
||||||
|
|
||||||
|
// Opening the Comments section shows comments regardless of the global setting.
|
||||||
|
await workspacePage.showComments();
|
||||||
|
await expect(bubble).toBeVisible();
|
||||||
|
|
||||||
|
// Closing the Comments section falls back to the (still disabled) global setting.
|
||||||
|
await workspacePage.showComments();
|
||||||
|
await expect(bubble).toBeHidden();
|
||||||
|
|
||||||
|
// The global setting itself must be untouched by opening/closing the section.
|
||||||
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await page.getByText("view").last().click();
|
||||||
|
await expect(page.locator("#file-menu-comments")).toContainText(
|
||||||
|
"Show comments",
|
||||||
|
);
|
||||||
|
await page.keyboard.press("Escape");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Comments stay visible through opening and closing the Comments section when the global setting is enabled", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const workspacePage = new WasmWorkspacePage(page);
|
||||||
|
await workspacePage.setupEmptyFile();
|
||||||
|
await workspacePage.setupFileWithComments();
|
||||||
|
await workspacePage.goToWorkspace();
|
||||||
|
|
||||||
|
const bubble = page.getByTestId("floating-thread-bubble-1");
|
||||||
|
|
||||||
|
// "Display comments" is enabled by default.
|
||||||
|
await expect(bubble).toBeVisible();
|
||||||
|
|
||||||
|
await workspacePage.showComments();
|
||||||
|
await expect(bubble).toBeVisible();
|
||||||
|
|
||||||
|
await workspacePage.showComments();
|
||||||
|
await expect(bubble).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await page.getByText("view").last().click();
|
||||||
|
await expect(page.locator("#file-menu-comments")).toContainText(
|
||||||
|
"Hide comments",
|
||||||
|
);
|
||||||
|
await page.keyboard.press("Escape");
|
||||||
|
});
|
||||||
|
|||||||
@ -15,7 +15,6 @@
|
|||||||
[app.main.data.workspace.drawing.common :as common]
|
[app.main.data.workspace.drawing.common :as common]
|
||||||
[app.main.data.workspace.drawing.curve :as curve]
|
[app.main.data.workspace.drawing.curve :as curve]
|
||||||
[app.main.data.workspace.drawing.line :as line]
|
[app.main.data.workspace.drawing.line :as line]
|
||||||
[app.main.data.workspace.layout :as dwlo]
|
|
||||||
[app.main.data.workspace.path :as path]
|
[app.main.data.workspace.path :as path]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
@ -47,11 +46,6 @@
|
|||||||
(when (= tool :path)
|
(when (= tool :path)
|
||||||
(rx/of (start-drawing :path)))
|
(rx/of (start-drawing :path)))
|
||||||
|
|
||||||
;; NOTE: comments are a special case and they manage they
|
|
||||||
;; own interrupt cycle.
|
|
||||||
(when (= tool :comments)
|
|
||||||
(rx/of (dwlo/toggle-layout-flag :display-comments :force? true)))
|
|
||||||
|
|
||||||
(when (and (not= tool :comments)
|
(when (and (not= tool :comments)
|
||||||
(not= tool :path))
|
(not= tool :path))
|
||||||
(let [stopper (rx/filter (ptk/type? ::clear-drawing) stream)]
|
(let [stopper (rx/filter (ptk/type? ::clear-drawing) stream)]
|
||||||
|
|||||||
@ -539,9 +539,10 @@
|
|||||||
(let [objects (dsh/lookup-page-objects state)
|
(let [objects (dsh/lookup-page-objects state)
|
||||||
selected-ids (dsh/lookup-selected state)
|
selected-ids (dsh/lookup-selected state)
|
||||||
selected-shapes (map (d/getf objects) selected-ids)
|
selected-shapes (map (d/getf objects) selected-ids)
|
||||||
add-new-variant? (every? ctc/is-variant? selected-shapes)
|
add-new-variant? (and (seq selected-shapes) (every? ctc/is-variant? selected-shapes))
|
||||||
undo-id (js/Symbol)]
|
undo-id (js/Symbol)]
|
||||||
(if add-new-variant?
|
(cond
|
||||||
|
add-new-variant?
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of
|
(rx/of
|
||||||
(ev/event {::ev/name "add-new-variant" ::ev/origin "workspace:shortcut-duplicate"})
|
(ev/event {::ev/name "add-new-variant" ::ev/origin "workspace:shortcut-duplicate"})
|
||||||
@ -549,7 +550,12 @@
|
|||||||
(add-new-variant (first selected-ids) false))
|
(add-new-variant (first selected-ids) false))
|
||||||
(rx/from (map #(add-new-variant % true) (rest selected-ids)))
|
(rx/from (map #(add-new-variant % true) (rest selected-ids)))
|
||||||
(rx/of (dwu/commit-undo-transaction undo-id)))
|
(rx/of (dwu/commit-undo-transaction undo-id)))
|
||||||
(rx/of (dws/duplicate-selected true)))))))
|
|
||||||
|
(seq selected-ids)
|
||||||
|
(rx/of (dws/duplicate-selected true))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(rx/empty))))))
|
||||||
|
|
||||||
(defn rename-variant
|
(defn rename-variant
|
||||||
"Rename the variant container and all components belonging to this variant"
|
"Rename the variant container and all components belonging to this variant"
|
||||||
|
|||||||
@ -136,7 +136,9 @@
|
|||||||
(repo/cmd! :get-page {:file-id file-id
|
(repo/cmd! :get-page {:file-id file-id
|
||||||
:page-id page-id
|
:page-id page-id
|
||||||
:share-id share-id
|
:share-id share-id
|
||||||
:object-id object-id
|
:object-id (if (uuid? object-id)
|
||||||
|
object-id
|
||||||
|
(set object-id))
|
||||||
:features features}))
|
:features features}))
|
||||||
(rx/tap (fn [[fonts]]
|
(rx/tap (fn [[fonts]]
|
||||||
(when (seq fonts)
|
(when (seq fonts)
|
||||||
@ -155,7 +157,7 @@
|
|||||||
[:embed {:optional true} :boolean]
|
[:embed {:optional true} :boolean]
|
||||||
[:skip-children {:optional true} :boolean]
|
[:skip-children {:optional true} :boolean]
|
||||||
[:object-id
|
[:object-id
|
||||||
[:or [::sm/set ::sm/uuid] ::sm/uuid]]])
|
[:or [:vector ::sm/uuid] ::sm/uuid]]])
|
||||||
|
|
||||||
(def ^:private coerce-render-objects-params
|
(def ^:private coerce-render-objects-params
|
||||||
(sm/coercer schema:render-objects))
|
(sm/coercer schema:render-objects))
|
||||||
@ -188,7 +190,7 @@
|
|||||||
{:file-id file-id
|
{:file-id file-id
|
||||||
:page-id page-id
|
:page-id page-id
|
||||||
:share-id share-id
|
:share-id share-id
|
||||||
:object-ids (into #{} object-id)
|
:object-ids (into [] (distinct) object-id)
|
||||||
:embed embed
|
:embed embed
|
||||||
:skip-children skip-children
|
:skip-children skip-children
|
||||||
:wasm wasm
|
:wasm wasm
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user