diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index bfa0276ce9..94ee1b5efa 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1253,10 +1253,18 @@ no-bool-shapes? (->> all-selected (some (comp #{:frame :text} :type)))] - (if (and (some? shape) (not (contains? selected (:id shape)))) + (cond + ;; A shape missing from the current page can never become + ;; selected, so selecting it and retrying would recurse forever + (and (some? shape) (not (contains? objects (:id shape)))) + (rx/empty) + + (and (some? shape) (not (contains? selected (:id shape)))) (rx/concat (rx/of (dws/select-shape (:id shape))) (rx/of (show-shape-context-menu params))) + + :else (rx/of (show-context-menu (-> params (assoc diff --git a/frontend/test/frontend_tests/data/workspace_context_menu_test.cljs b/frontend/test/frontend_tests/data/workspace_context_menu_test.cljs new file mode 100644 index 0000000000..f0e1783293 --- /dev/null +++ b/frontend/test/frontend_tests/data/workspace_context_menu_test.cljs @@ -0,0 +1,69 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC Sucursal en EspaƱa SL + +(ns frontend-tests.data.workspace-context-menu-test + (:require + [app.common.geom.point :as gpt] + [app.common.uuid :as uuid] + [app.main.data.workspace :as dw] + [app.main.data.workspace.selection :as dws] + [beicon.v2.core :as rx] + [cljs.test :as t :include-macros true] + [potok.v2.core :as ptk])) + +(def ^:private file-id (uuid/next)) +(def ^:private page-id (uuid/next)) +(def ^:private rect-id (uuid/next)) + +(defn- make-state + [selected] + {:current-file-id file-id + :current-page-id page-id + :workspace-local {:selected selected} + :files {file-id + {:data + {:pages-index + {page-id + {:objects {uuid/zero {:id uuid/zero :type :frame :shapes [rect-id]} + rect-id {:id rect-id :type :rect :parent-id uuid/zero + :frame-id uuid/zero}}}}}}}}) + +(defn- emitted-types + "Collect the types of the events emitted by the event's watch." + [event state done f] + (let [types (atom [])] + (->> (ptk/watch event state (rx/empty)) + (rx/subs! + #(swap! types conj (ptk/type %)) + (fn [err] + (t/do-report {:type :error :message "Stream error" :actual err}) + (done)) + (fn [] + (f @types) + (done)))))) + +(defn- menu-event + [shape-id] + (dw/show-shape-context-menu {:position (gpt/point 10 10) + :shape {:id shape-id :type :rect}})) + +(t/deftest shape-context-menu-ignores-shape-outside-page + (t/async + done + (emitted-types (menu-event (uuid/next)) (make-state #{}) done + #(t/is (= [] %))))) + +(t/deftest shape-context-menu-selects-unselected-shape + (t/async + done + (emitted-types (menu-event rect-id) (make-state #{}) done + #(t/is (= [::dws/select-shape ::dw/show-shape-context-menu] %))))) + +(t/deftest shape-context-menu-opens-for-selected-shape + (t/async + done + (emitted-types (menu-event rect-id) (make-state #{rect-id}) done + #(t/is (= [::dw/show-context-menu] %))))) diff --git a/frontend/test/frontend_tests/runner.cljs b/frontend/test/frontend_tests/runner.cljs index 96b79f0419..31ef564cba 100644 --- a/frontend/test/frontend_tests/runner.cljs +++ b/frontend/test/frontend_tests/runner.cljs @@ -19,6 +19,7 @@ [frontend-tests.data.viewer-test] [frontend-tests.data.workspace-colors-test] [frontend-tests.data.workspace-comments-test] + [frontend-tests.data.workspace-context-menu-test] [frontend-tests.data.workspace-interactions-test] [frontend-tests.data.workspace-mcp-test] [frontend-tests.data.workspace-media-test] @@ -123,6 +124,7 @@ 'frontend-tests.data.viewer-test 'frontend-tests.data.workspace-colors-test 'frontend-tests.data.workspace-comments-test + 'frontend-tests.data.workspace-context-menu-test 'frontend-tests.data.workspace-interactions-test 'frontend-tests.data.workspace-mcp-test 'frontend-tests.data.workspace-media-test