diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index 322a3dd5fc..fc41156ca1 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -908,10 +908,6 @@ ::oapi/format "password"}}) -;; FIXME: this should not be here -(register! ::plugin-data - [:map-of {:gen/max 5} :string :string]) - ;; ---- PREDICATES (def valid-safe-number? diff --git a/common/src/app/common/types/color.cljc b/common/src/app/common/types/color.cljc index 64c8571612..5ab2dc6355 100644 --- a/common/src/app/common/types/color.cljc +++ b/common/src/app/common/types/color.cljc @@ -14,6 +14,7 @@ [app.common.types.color.generic :as-alias color-generic] [app.common.types.color.gradient :as-alias color-gradient] [app.common.types.color.gradient.stop :as-alias color-gradient-stop] + [app.common.types.plugins :as ctpg] [app.common.uuid :as uuid] [clojure.test.check.generators :as tgen] [cuerdas.core :as str])) @@ -88,7 +89,7 @@ [:gradient {:optional true} [:maybe ::gradient]] [:image {:optional true} [:maybe ::image-color]] [:plugin-data {:optional true} - [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]] + [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]] [::sm/contains-any {:strict true} [:color :gradient :image]]]) (sm/register! ::recent-color diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index d8aa12b938..aedf4ebc26 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -15,6 +15,7 @@ [app.common.types.component :as ctk] [app.common.types.components-list :as ctkl] [app.common.types.pages-list :as ctpl] + [app.common.types.plugins :as ctpg] [app.common.types.shape-tree :as ctst] [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid])) @@ -37,7 +38,7 @@ [:objects {:optional true} [:map-of {:gen/max 10} ::sm/uuid :map]] [:plugin-data {:optional true} - [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]]) + [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]]) (def check-container! (sm/check-fn ::container)) diff --git a/common/src/app/common/types/file.cljc b/common/src/app/common/types/file.cljc index b7f7acd7dc..1a411f594f 100644 --- a/common/src/app/common/types/file.cljc +++ b/common/src/app/common/types/file.cljc @@ -24,6 +24,7 @@ [app.common.types.container :as ctn] [app.common.types.page :as ctp] [app.common.types.pages-list :as ctpl] + [app.common.types.plugins :as ctpg] [app.common.types.shape-tree :as ctst] [app.common.types.typographies-list :as ctyl] [app.common.types.typography :as cty] @@ -59,7 +60,7 @@ [:media {:optional true} [:map-of {:gen/max 5} ::sm/uuid ::media-object]] [:plugin-data {:optional true} - [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]]) + [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]]) (def check-file-data! (sm/check-fn ::data)) diff --git a/common/src/app/common/types/page.cljc b/common/src/app/common/types/page.cljc index b8c9eb3de6..3b00643ce0 100644 --- a/common/src/app/common/types/page.cljc +++ b/common/src/app/common/types/page.cljc @@ -10,6 +10,7 @@ [app.common.schema :as sm] [app.common.types.color :as-alias ctc] [app.common.types.grid :as ctg] + [app.common.types.plugins :as ctpg] [app.common.types.shape :as cts] [app.common.uuid :as uuid])) @@ -45,7 +46,7 @@ [:guides {:optional true} [:map-of {:gen/max 2} ::sm/uuid ::guide]] [:plugin-data {:optional true} - [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]]]]) + [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]]]]) (def check-page-guide! (sm/check-fn ::guide)) diff --git a/common/src/app/common/types/plugins.cljc b/common/src/app/common/types/plugins.cljc new file mode 100644 index 0000000000..49d31bf2d6 --- /dev/null +++ b/common/src/app/common/types/plugins.cljc @@ -0,0 +1,16 @@ +;; 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.common.types.plugins + (:require + [app.common.schema :as sm])) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; SCHEMAS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(sm/register! ::plugin-data + [:map-of {:gen/max 5} :string :string]) diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index 71a1964d39..cbce60984c 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -20,6 +20,7 @@ [app.common.transit :as t] [app.common.types.color :as ctc] [app.common.types.grid :as ctg] + [app.common.types.plugins :as ctpg] [app.common.types.shape.attrs :refer [default-color]] [app.common.types.shape.blur :as ctsb] [app.common.types.shape.export :as ctse] @@ -188,7 +189,7 @@ [:grow-type {:optional true} [::sm/one-of #{:auto-width :auto-height :fixed}]] [:plugin-data {:optional true} - [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]]) + [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]]) (sm/register! ::group-attrs [:map {:title "GroupAttrs"} diff --git a/common/src/app/common/types/typography.cljc b/common/src/app/common/types/typography.cljc index ba9eb12906..e143a2b8b7 100644 --- a/common/src/app/common/types/typography.cljc +++ b/common/src/app/common/types/typography.cljc @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.schema :as sm] [app.common.text :as txt] + [app.common.types.plugins :as ctpg] [app.common.uuid :as uuid])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -31,7 +32,7 @@ [:modified-at {:optional true} ::sm/inst] [:path {:optional true} [:maybe :string]] [:plugin-data {:optional true} - [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]]) + [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]]) (def check-typography! (sm/check-fn ::typography)) diff --git a/frontend/resources/images/icons/puzzle.svg b/frontend/resources/images/icons/puzzle.svg index 6e978bac53..ceef3a54b4 100644 --- a/frontend/resources/images/icons/puzzle.svg +++ b/frontend/resources/images/icons/puzzle.svg @@ -1 +1 @@ - + diff --git a/frontend/resources/plugins-runtime/index.js b/frontend/resources/plugins-runtime/index.js index 1d75c17b15..8b622aa539 100644 --- a/frontend/resources/plugins-runtime/index.js +++ b/frontend/resources/plugins-runtime/index.js @@ -7776,6 +7776,9 @@ function Ml(t, e) { get selection() { return o("content:read"), t.selection; }, + set selection(i) { + o("content:read"), t.selection = i; + }, get viewport() { return t.viewport; }, diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs index 286a179038..58d702f8b9 100644 --- a/frontend/src/app/config.cljs +++ b/frontend/src/app/config.cljs @@ -110,7 +110,7 @@ (def privacy-policy-uri (obj/get global "penpotPrivacyPolicyURI" "https://penpot.app/privacy")) (def flex-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/")) (def grid-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/")) -(def plugins-list-uri (obj/get global "penpotPluginsListUri" "https://penpot-docs-plugins.netlify.app/technical-guide/plugins/getting-started/#examples")) +(def plugins-list-uri (obj/get global "penpotPluginsListUri" "https://penpot-docs-plugins.pages.dev/technical-guide/plugins/getting-started/#examples")) (defn- normalize-uri [uri-str] diff --git a/frontend/src/app/main/data/workspace/media.cljs b/frontend/src/app/main/data/workspace/media.cljs index d97d0b8035..b3f5d48ec6 100644 --- a/frontend/src/app/main/data/workspace/media.cljs +++ b/frontend/src/app/main/data/workspace/media.cljs @@ -467,4 +467,5 @@ (watch [_ _ _] (->> (svg->clj [name svg-string]) (rx/take 1) - (rx/map #(svg/add-svg-shapes id % position {:change-selection? false})))))) + (rx/map #(svg/add-svg-shapes id % position {:ignore-selection? true + :change-selection? false})))))) diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs index bd0071602e..87346de670 100644 --- a/frontend/src/app/main/data/workspace/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/shortcuts.cljs @@ -27,7 +27,8 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.hooks.resize :as r] - [app.util.dom :as dom])) + [app.util.dom :as dom] + [potok.v2.core :as ptk])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Shortcuts @@ -563,7 +564,9 @@ :command (ds/c-mod "alt+p") :subsections [:basics] :fn #(when (features/active-feature? @st/state "plugins/runtime") - (st/emit! (modal/show :plugin-management {})))}}) + (st/emit! + (ptk/event ::ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:shortcuts"}) + (modal/show :plugin-management {})))}}) (def debug-shortcuts ;; PREVIEW diff --git a/frontend/src/app/main/data/workspace/svg_upload.cljs b/frontend/src/app/main/data/workspace/svg_upload.cljs index a11f8893bb..169e2dd3ed 100644 --- a/frontend/src/app/main/data/workspace/svg_upload.cljs +++ b/frontend/src/app/main/data/workspace/svg_upload.cljs @@ -64,7 +64,8 @@ ([svg-data position] (add-svg-shapes nil svg-data position nil)) - ([id svg-data position {:keys [change-selection?] :or {change-selection? false}}] + ([id svg-data position {:keys [change-selection? ignore-selection?] + :or {ignore-selection? false change-selection? true}}] (ptk/reify ::add-svg-shapes ptk/WatchEvent (watch [it state _] @@ -73,7 +74,7 @@ page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) frame-id (ctst/top-nested-frame objects position) - selected (wsh/lookup-selected state) + selected (if ignore-selection? #{} (wsh/lookup-selected state)) base (cfh/get-base-shape objects selected) selected-id (first selected) diff --git a/frontend/src/app/main/ui/workspace/main_menu.cljs b/frontend/src/app/main/ui/workspace/main_menu.cljs index 135cdc1b59..ea0fc54f41 100644 --- a/frontend/src/app/main/ui/workspace/main_menu.cljs +++ b/frontend/src/app/main/ui/workspace/main_menu.cljs @@ -630,13 +630,23 @@ (when (d/not-empty? plugins) [:div {:class (stl/css :separator)}]) - (for [[idx {:keys [name] :as manifest}] (d/enumerate plugins)] + (for [[idx {:keys [name host] :as manifest}] (d/enumerate plugins)] [:> dropdown-menu-item* {:key (dm/str "plugins-menu-" idx) - :on-click #(uwp/open-plugin! manifest) + :on-click #(do + (st/emit! (ptk/event ::ev/event {::ev/name "start-plugin" + ::ev/origin "workspace:menu" + :name name + :host host})) + (uwp/open-plugin! manifest)) :class (stl/css :submenu-item) :on-key-down (fn [event] (when (kbd/enter? event) - #(uwp/open-plugin! manifest)))} + #(do + (st/emit! (ptk/event ::ev/event {::ev/name "start-plugin" + ::ev/origin "workspace:menu" + :name name + :host host})) + (uwp/open-plugin! manifest))))} [:span {:class (stl/css :item-name)} name]])]))) (mf/defc menu @@ -699,7 +709,9 @@ (dom/stop-propagation event) (reset! show-menu* false) (reset! sub-menu* nil) - (st/emit! (modal/show :plugin-management {}))))] + (st/emit! + (ptk/event ::ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:menu"}) + (modal/show :plugin-management {}))))] [:* diff --git a/frontend/src/app/main/ui/workspace/plugins.cljs b/frontend/src/app/main/ui/workspace/plugins.cljs index d7db43950c..7a71cf4a00 100644 --- a/frontend/src/app/main/ui/workspace/plugins.cljs +++ b/frontend/src/app/main/ui/workspace/plugins.cljs @@ -10,6 +10,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.config :as cf] + [app.main.data.events :as ev] [app.main.data.modal :as modal] [app.main.store :as st] [app.main.ui.components.search-bar :refer [search-bar]] @@ -21,6 +22,8 @@ [app.util.http :as http] [app.util.i18n :as i18n :refer [tr]] [beicon.v2.core :as rx] + [cuerdas.core :as str] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (def ^:private close-icon @@ -111,6 +114,7 @@ (rx/subs! (fn [body] (let [plugin (plugins/parser-manifest plugin-url body)] + (st/emit! (ptk/event ::ev/event {::ev/name "install-plugin" :name (:name plugin) :url plugin-url})) (modal/show! :plugin-permissions {:plugin plugin @@ -126,6 +130,10 @@ handle-open-plugin (mf/use-callback (fn [manifest] + (st/emit! (ptk/event ::ev/event {::ev/name "start-plugin" + ::ev/origin "workspace:plugins" + :name (:name manifest) + :host (:host manifest)})) (open-plugin! manifest) (modal/hide!))) @@ -134,6 +142,9 @@ (mf/deps plugins-state) (fn [plugin-index] (let [plugin (nth @plugins/pluginsdb plugin-index)] + (st/emit! (ptk/event ::ev/event {::ev/name "remove-plugin" + :name (:name plugin) + :host (:host plugin)})) (plugins/remove-plugin! plugin) (reset! plugins-state* @plugins/pluginsdb))))] @@ -162,7 +173,10 @@ [:div {:class (stl/css :plugins-empty)} [:div {:class (stl/css :plugins-empty-logo)} i/puzzle] [:div {:class (stl/css :plugins-empty-text)} (tr "workspace.plugins.empty-plugins")] - [:a {:class (stl/css :plugins-link) :href cf/plugins-list-uri :target "_blank"} + [:a {:class (stl/css :plugins-link) + :href cf/plugins-list-uri + :target "_blank" + :on-click #(st/emit! (ptk/event ::ev/event {::ev/name "open-plugins-list"}))} (tr "workspace.plugins.plugin-list-link") i/external-link]] [:* @@ -182,7 +196,7 @@ ::mf/register-as :plugin-permissions} [{:keys [plugin on-accept]}] - (let [{:keys [permissions]} plugin + (let [{:keys [host permissions]} plugin permissions (set permissions) handle-accept-dialog @@ -190,12 +204,18 @@ (fn [event] (dom/prevent-default event) (st/emit! (modal/hide)) + (ptk/event ::ev/event {::ev/name "allow-plugin-permissions" + :host host + :permissions (->> permissions (str/join ", "))}) (on-accept))) handle-close-dialog (mf/use-callback (fn [event] (dom/prevent-default event) + (ptk/event ::ev/event {::ev/name "reject-plugin-permissions" + :host host + :permissions (->> permissions (str/join ", "))}) (st/emit! (modal/hide))))] [:div {:class (stl/css :modal-overlay)} @@ -205,35 +225,38 @@ [:div {:class (stl/css :modal-content)} [:div {:class (stl/css :permissions-list)} - (when (contains? permissions "content:read") + (cond + (contains? permissions "content:write") + [:div {:class (stl/css :permissions-list-entry)} + i/oauth-1 + [:p {:class (stl/css :permissions-list-text)} + (tr "workspace.plugins.permissions.content-write")]] + + (contains? permissions "content:read") [:div {:class (stl/css :permissions-list-entry)} i/oauth-1 [:p {:class (stl/css :permissions-list-text)} (tr "workspace.plugins.permissions.content-read")]]) - (when (contains? permissions "content:write") - [:div {:class (stl/css :permissions-list-entry)} - i/oauth-1 - [:p {:class (stl/css :permissions-list-text)} - (tr "workspace.plugins.permissions.content-write")]]) - - (when (contains? permissions "user:read") + (cond + (contains? permissions "user:read") [:div {:class (stl/css :permissions-list-entry)} i/oauth-2 [:p {:class (stl/css :permissions-list-text)} (tr "workspace.plugins.permissions.user-read")]]) - (when (contains? permissions "library:read") + (cond + (contains? permissions "library:write") [:div {:class (stl/css :permissions-list-entry)} i/oauth-3 [:p {:class (stl/css :permissions-list-text)} - (tr "workspace.plugins.permissions.library-read")]]) + (tr "workspace.plugins.permissions.library-write")]] - (when (contains? permissions "library:write") + (contains? permissions "library:read") [:div {:class (stl/css :permissions-list-entry)} i/oauth-3 [:p {:class (stl/css :permissions-list-text)} - (tr "workspace.plugins.permissions.library-write")]])] + (tr "workspace.plugins.permissions.library-read")]])] [:div {:class (stl/css :permissions-disclaimer)} (tr "workspace.plugins.permissions.disclaimer")]] diff --git a/frontend/src/app/main/ui/workspace/top_toolbar.cljs b/frontend/src/app/main/ui/workspace/top_toolbar.cljs index dfbb3fe1ae..82e3444452 100644 --- a/frontend/src/app/main/ui/workspace/top_toolbar.cljs +++ b/frontend/src/app/main/ui/workspace/top_toolbar.cljs @@ -27,6 +27,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.timers :as ts] [okulary.core :as l] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc image-upload @@ -200,7 +201,9 @@ {:title (tr "workspace.toolbar.plugins" (sc/get-tooltip :plugins)) :aria-label (tr "workspace.toolbar.plugins" (sc/get-tooltip :plugins)) :class (stl/css :main-toolbar-options-button) - :on-click #(modal/show! :plugin-management {}) + :on-click #(st/emit! + (ptk/event ::ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:toolbar"}) + (modal/show :plugin-management {})) :data-tool "plugins" :data-testid "plugins-btn"} i/puzzle]]) diff --git a/frontend/src/app/plugins.cljs b/frontend/src/app/plugins.cljs index 21e16d3c20..c66260e522 100644 --- a/frontend/src/app/plugins.cljs +++ b/frontend/src/app/plugins.cljs @@ -47,7 +47,16 @@ desc (obj/get manifest "description") code (obj/get manifest "code") icon (obj/get manifest "icon") - permissions (obj/get manifest "permissions") + + permissions (into #{} (obj/get manifest "permissions" [])) + permissions + (cond-> permissions + (contains? permissions "content:write") + (conj "content:read") + + (contains? permissions "library:write") + (conj "content:write")) + origin (obj/get (js/URL. plugin-url) "origin") plugin-id (str (uuid/next))] {:plugin-id plugin-id diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index 2cd3938a7f..076c9f0fa4 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -23,6 +23,7 @@ [app.main.data.workspace.colors :as dwc] [app.main.data.workspace.groups :as dwg] [app.main.data.workspace.media :as dwm] + [app.main.data.workspace.selection :as dws] [app.main.store :as st] [app.plugins.events :as events] [app.plugins.file :as file] @@ -356,7 +357,19 @@ {:name "root" :get #(.getRoot ^js %)} {:name "currentFile" :get #(.getFile ^js %)} {:name "currentPage" :get #(.getPage ^js %)} - {:name "selection" :get #(.getSelectedShapes ^js %)} + + {:name "selection" + :get #(.getSelectedShapes ^js %) + :set + (fn [_ shapes] + (cond + (or (not (array? shapes)) (not (every? shape/shape-proxy? shapes))) + (u/display-not-valid :selection shapes) + + :else + (let [ids (into (d/ordered-set) (map #(obj/get % "$id")) shapes)] + (st/emit! (dws/select-shapes ids)))))} + {:name "viewport" :get #(.getViewport ^js %)} {:name "currentUser" :get #(.getCurrentUser ^js %)} {:name "activeUsers" :get #(.getActiveUsers ^js %)} diff --git a/frontend/src/app/plugins/parser.cljs b/frontend/src/app/plugins/parser.cljs index 3180a0e4b7..53092c5697 100644 --- a/frontend/src/app/plugins/parser.cljs +++ b/frontend/src/app/plugins/parser.cljs @@ -229,8 +229,8 @@ (when (some? export) (d/without-nils {:type (-> (obj/get export "type") parse-keyword) - :scale (obj/get export "scale") - :suffix (obj/get export "suffix")}))) + :scale (obj/get export "scale" 1) + :suffix (obj/get export "suffix" "")}))) (defn parse-exports [^js exports] diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 727b2c70c9..2ae9b0d399 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -36,6 +36,7 @@ [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.texts :as dwt] + [app.main.repo :as rp] [app.main.store :as st] [app.plugins.flex :as flex] [app.plugins.format :as format] @@ -46,7 +47,9 @@ [app.plugins.utils :as u] [app.util.object :as obj] [app.util.path.format :as upf] - [cuerdas.core :as str])) + [beicon.v2.core :as rx] + [cuerdas.core :as str] + [promesa.core :as p])) (def lib-typography-proxy? nil) (def lib-component-proxy nil) @@ -436,7 +439,34 @@ shape (u/proxy->shape self)] (when (ctn/in-any-component? objects shape) (let [[root component] (u/locate-component objects shape)] - (lib-component-proxy $plugin (:component-file root) (:id component))))))) + (lib-component-proxy $plugin (:component-file root) (:id component)))))) + + (export + [self value] + (let [value (parser/parse-export value)] + (cond + (not (sm/validate ::ctse/export value)) + (u/display-not-valid :export value) + + :else + (let [payload + {:cmd :export-shapes + :profile-id (:profile-id @st/state) + :wait true + :exports [{:file-id $file + :page-id $page + :object-id $id + :name (obj/get self "name") + :type (:type value :png) + :suffix (:suffix value "") + :scale (:scale value 1)}]}] + (p/create + (fn [resolve reject] + (->> (rp/cmd! :export payload) + (rx/mapcat #(rp/cmd! :export {:cmd :get-resource :wait true :id (:id %) :blob? true})) + (rx/mapcat #(.arrayBuffer %)) + (rx/map #(js/Uint8Array. %)) + (rx/subs! resolve reject))))))))) (defn shape-proxy? [p] (instance? ShapeProxy p)) @@ -886,6 +916,12 @@ {:name "height" :get #(-> % u/proxy->shape :height)} + {:name "bounds" + :get #(-> % u/proxy->shape :points grc/points->rect format/format-bounds)} + + {:name "center" + :get #(-> % u/proxy->shape gsh/shape->center format/format-point)} + {:name "rotation" :get #(-> % u/proxy->shape :rotation) :set diff --git a/frontend/test/frontend_tests/helpers/state.cljs b/frontend/test/frontend_tests/helpers/state.cljs index 6c3c7cb2c7..37d245df5c 100644 --- a/frontend/test/frontend_tests/helpers/state.cljs +++ b/frontend/test/frontend_tests/helpers/state.cljs @@ -39,21 +39,25 @@ store)) (defn run-store - [store done events completed-cb] - (let [stream (ptk/input-stream store)] - (->> stream - (rx/take-until (rx/filter #(= :the/end %) stream)) - (rx/last) - (rx/tap (fn [] - (completed-cb @store))) - (rx/subs! (fn [_] (done)) - (fn [cause] - (js/console.log "[error]:" cause)) - (fn [_] - (js/console.log "[complete]")))) - (doall (for [event events] - (ptk/emit! store event))) - (ptk/emit! store :the/end))) + ([store done events completed-cb] + (run-store store done events completed-cb nil)) + ([store done events completed-cb stopper] + (let [stream (ptk/input-stream store)] + (->> stream + (rx/take-until (if stopper + (stopper stream) + (rx/filter #(= :the/end %) stream))) + (rx/last) + (rx/tap (fn [] + (completed-cb @store))) + (rx/subs! (fn [_] (done)) + (fn [cause] + (js/console.log "[error]:" cause)) + (fn [_] + (js/console.log "[complete]")))) + (doall (for [event events] + (ptk/emit! store event))) + (ptk/emit! store :the/end)))) (defn get-file-from-store [store] diff --git a/frontend/translations/en.po b/frontend/translations/en.po index b05464a4c9..5e90a19512 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5281,6 +5281,9 @@ msgstr "Plugin correctly loaded." msgid "workspace.plugins.menu.title" msgstr "Plugins" +msgid "workspace.toolbar.plugins" +msgstr "Plugins" + msgid "workspace.plugins.menu.plugins-manager" msgstr "Plugins manager" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index c226af8922..407f37cd58 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -5361,6 +5361,9 @@ msgstr "Pulsar para cerrar la ruta" msgid "workspace.plugins.title" msgstr "Extensiones" +msgid "workspace.toolbar.plugins" +msgstr "Extensiones" + msgid "workspace.plugins.search-placeholder" msgstr "Intruduzca URL de la extensión"