mirror of
https://github.com/penpot/penpot.git
synced 2025-01-21 06:02:32 -05:00
Merge pull request #5261 from penpot/palba-viewer-and-plugins
✨ Integrate viewer role with plugin menus and popup
This commit is contained in:
commit
960f095c1b
10 changed files with 168 additions and 36 deletions
|
@ -8,13 +8,23 @@
|
|||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.register :as preg]
|
||||
[app.util.globals :as ug]
|
||||
[app.util.http :as http]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.time :as dt]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
(defn save-plugin-permissions-peek
|
||||
[id permissions]
|
||||
(ptk/reify ::save-plugin-permissions-peek
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:plugins-permissions-peek :data id] permissions))))
|
||||
|
||||
(defn fetch-manifest
|
||||
[plugin-url]
|
||||
(->> (http/send! {:method :get
|
||||
|
@ -59,15 +69,21 @@
|
|||
(.error js/console "Error" e))))
|
||||
|
||||
(defn open-plugin!
|
||||
[{:keys [url] :as manifest}]
|
||||
[{:keys [url] :as manifest} user-can-edit?]
|
||||
(if url
|
||||
;; If the saved manifest has a URL we fetch the manifest to check
|
||||
;; for updates
|
||||
(->> (fetch-manifest url)
|
||||
(rx/subs!
|
||||
(fn [new-manifest]
|
||||
(let [new-manifest (merge new-manifest (select-keys manifest [:plugin-id]))]
|
||||
(let [new-manifest (merge new-manifest (select-keys manifest [:plugin-id]))
|
||||
permissions (:permissions new-manifest)
|
||||
is-edition-plugin? (or (contains? permissions "content:write")
|
||||
(contains? permissions "library:write"))]
|
||||
(st/emit! (save-plugin-permissions-peek (:plugin-id new-manifest) permissions))
|
||||
(cond
|
||||
(and is-edition-plugin? (not user-can-edit?))
|
||||
(st/emit! (ntf/warn (tr "workspace.plugins.error.need-editor")))
|
||||
(not= (:permissions new-manifest) (:permissions manifest))
|
||||
(modal/show!
|
||||
:plugin-permissions-update
|
||||
|
@ -96,13 +112,21 @@
|
|||
(.error js/console "Error" e))))
|
||||
|
||||
(defn close-current-plugin
|
||||
[]
|
||||
[& {:keys [close-only-edition-plugins?]}]
|
||||
(ptk/reify ::close-current-plugin
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [ids (dm/get-in state [:workspace-local :open-plugins])]
|
||||
(doseq [id ids]
|
||||
(close-plugin! (preg/get-plugin id)))))))
|
||||
(let [plugin (preg/get-plugin id)
|
||||
permissions (or (dm/get-in state [:plugins-permissions-peek :data id])
|
||||
(:permissions plugin))
|
||||
is-edition-plugin? (or (contains? permissions "content:write")
|
||||
(contains? permissions "library:write"))]
|
||||
|
||||
(when (or (not close-only-edition-plugins?)
|
||||
is-edition-plugin?)
|
||||
(close-plugin! plugin))))))))
|
||||
|
||||
(defn delay-open-plugin
|
||||
[plugin]
|
||||
|
@ -116,6 +140,38 @@
|
|||
(ptk/reify ::check-open-plugin
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when-let [pid (::open-plugin state)]
|
||||
(open-plugin! (preg/get-plugin pid))
|
||||
(rx/of #(dissoc % ::open-plugin))))))
|
||||
(let [user-can-edit? (dm/get-in state [:permissions :can-edit])]
|
||||
(when-let [pid (::open-plugin state)]
|
||||
(open-plugin! (preg/get-plugin pid) user-can-edit?)
|
||||
(rx/of #(dissoc % ::open-plugin)))))))
|
||||
|
||||
(defn- update-plugin-permissions-peek
|
||||
[{:keys [plugin-id url]}]
|
||||
(when url
|
||||
;; If the saved manifest has a URL we fetch the manifest to check
|
||||
;; for updates
|
||||
(->> (fetch-manifest url)
|
||||
(rx/subs!
|
||||
(fn [new-manifest]
|
||||
(let [permissions (:permissions new-manifest)]
|
||||
(when permissions
|
||||
(st/emit! (save-plugin-permissions-peek plugin-id permissions)))))))))
|
||||
|
||||
(defn update-plugins-permissions-peek
|
||||
[]
|
||||
(ptk/reify ::update-plugins-permissions-peek
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [now (dt/now)
|
||||
expiration (dt/minus now (dt/duration {:days 1}))
|
||||
updated-at (dm/get-in state [:plugins-permissions-peek :updated-at] 0)
|
||||
expired? (> expiration updated-at)]
|
||||
|
||||
(if expired?
|
||||
(let [plugins (preg/plugins-list)]
|
||||
(doseq [plugin plugins]
|
||||
(update-plugin-permissions-peek plugin))
|
||||
(-> state
|
||||
(assoc-in [:plugins-permissions-peek :updated-at] now)))
|
||||
|
||||
state)))))
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[app.main.data.changes :as dch]
|
||||
[app.main.data.common :as dc]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.plugins :as dpl]
|
||||
[app.main.data.websocket :as dws]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.edition :as dwe]
|
||||
|
@ -117,7 +118,8 @@
|
|||
(rx/delay 100))
|
||||
(if (= :viewer role)
|
||||
(rx/of (modal/hide)
|
||||
(dwly/set-options-mode :inspect))
|
||||
(dwly/set-options-mode :inspect)
|
||||
(dpl/close-current-plugin {:close-only-edition-plugins? true}))
|
||||
(rx/of (dwly/set-options-mode :design)))))))
|
||||
|
||||
(defn- process-message
|
||||
|
|
|
@ -518,6 +518,11 @@
|
|||
(def workspace-selected-token-set-tokens
|
||||
(l/derived #(or (wtts/get-selected-token-set-tokens %) {}) st/state))
|
||||
|
||||
(def plugins-permissions-peek
|
||||
(l/derived (fn [state]
|
||||
(dm/get-in state [:plugins-permissions-peek :data]))
|
||||
st/state))
|
||||
|
||||
;; ---- Viewer refs
|
||||
|
||||
(defn lookup-viewer-objects-by-id
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.persistence :as dps]
|
||||
[app.main.data.plugins :as dpl]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.colors :as dc]
|
||||
[app.main.features :as features]
|
||||
|
@ -185,7 +186,8 @@
|
|||
background-color (:background-color wglobal)]
|
||||
|
||||
(mf/with-effect []
|
||||
(st/emit! (dps/initialize-persistence)))
|
||||
(st/emit! (dps/initialize-persistence)
|
||||
(dpl/update-plugins-permissions-peek)))
|
||||
|
||||
;; Setting the layout preset by its name
|
||||
(mf/with-effect [layout-name]
|
||||
|
|
|
@ -632,7 +632,9 @@
|
|||
::mf/wrap [mf/memo]}
|
||||
[{:keys [open-plugins on-close]}]
|
||||
(when (features/active-feature? @st/state "plugins/runtime")
|
||||
(let [plugins (preg/plugins-list)]
|
||||
(let [plugins (preg/plugins-list)
|
||||
user-can-edit? (:can-edit (deref refs/permissions))
|
||||
permissions-peek (deref refs/plugins-permissions-peek)]
|
||||
[:& dropdown-menu {:show true
|
||||
:list-class (stl/css-case :sub-menu true :plugins true)
|
||||
:on-close on-close}
|
||||
|
@ -653,24 +655,41 @@
|
|||
(when (d/not-empty? plugins)
|
||||
[:div {:class (stl/css :separator)}])
|
||||
|
||||
(for [[idx {:keys [name host] :as manifest}] (d/enumerate plugins)]
|
||||
[:> dropdown-menu-item* {:key (dm/str "plugins-menu-" idx)
|
||||
:on-click #(do
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:menu"
|
||||
:name name
|
||||
:host host}))
|
||||
(dp/open-plugin! manifest))
|
||||
:class (stl/css :submenu-item)
|
||||
:on-key-down (fn [event]
|
||||
(when (kbd/enter? event)
|
||||
#(do
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:menu"
|
||||
:name name
|
||||
:host host}))
|
||||
(dp/open-plugin! manifest))))}
|
||||
[:span {:class (stl/css :item-name)} name]])])))
|
||||
(for [[idx {:keys [plugin-id name host permissions] :as manifest}] (d/enumerate plugins)]
|
||||
(let [permissions (or (get permissions-peek plugin-id) permissions)
|
||||
is-edition-plugin? (or (contains? permissions "content:write")
|
||||
(contains? permissions "library:write"))
|
||||
can-open? (or user-can-edit?
|
||||
(not is-edition-plugin?))
|
||||
on-click
|
||||
(mf/use-fn
|
||||
(mf/deps can-open? name host manifest user-can-edit?)
|
||||
(fn [event]
|
||||
(if can-open?
|
||||
(do
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:menu"
|
||||
:name name
|
||||
:host host}))
|
||||
(dp/open-plugin! manifest user-can-edit?))
|
||||
(dom/stop-propagation event))))
|
||||
on-key-down
|
||||
(mf/use-fn
|
||||
(mf/deps can-open? name host manifest user-can-edit?)
|
||||
(fn [event]
|
||||
(when can-open?
|
||||
(when (kbd/enter? event)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:menu"
|
||||
:name name
|
||||
:host host}))
|
||||
(dp/open-plugin! manifest user-can-edit?)))))]
|
||||
[:> dropdown-menu-item* {:key (dm/str "plugins-menu-" idx)
|
||||
:on-click on-click
|
||||
:title (when-not can-open? (tr "workspace.plugins.error.need-editor"))
|
||||
:class (stl/css-case :submenu-item true :menu-disabled (not can-open?))
|
||||
:on-key-down on-key-down}
|
||||
[:span {:class (stl/css :item-name)} name]]))])))
|
||||
|
||||
(mf/defc menu
|
||||
{::mf/props :obj}
|
||||
|
|
|
@ -17,20 +17,25 @@
|
|||
.menu-item {
|
||||
@extend .menu-item-base;
|
||||
cursor: pointer;
|
||||
|
||||
.open-arrow {
|
||||
@include flexCenter;
|
||||
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--menu-foreground-color-hover);
|
||||
|
||||
.open-arrow {
|
||||
svg {
|
||||
stroke: var(--menu-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-key {
|
||||
color: var(--menu-shortcut-foreground-color-hover);
|
||||
}
|
||||
|
@ -46,6 +51,7 @@
|
|||
.shortcut {
|
||||
@extend .shortcut-base;
|
||||
}
|
||||
|
||||
.shortcut-key {
|
||||
@extend .shortcut-key-base;
|
||||
}
|
||||
|
@ -59,14 +65,26 @@
|
|||
|
||||
.submenu-item {
|
||||
@extend .menu-item-base;
|
||||
|
||||
&:hover {
|
||||
color: var(--menu-foreground-color-hover);
|
||||
|
||||
.shortcut-key {
|
||||
color: var(--menu-shortcut-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-disabled {
|
||||
color: var(--color-foreground-secondary);
|
||||
|
||||
&:hover {
|
||||
cursor: default;
|
||||
color: var(--color-foreground-secondary);
|
||||
background-color: var(--menu-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.file {
|
||||
top: $s-48;
|
||||
}
|
||||
|
|
|
@ -13,9 +13,11 @@
|
|||
[app.main.data.events :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.plugins :as dp]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.search-bar :refer [search-bar]]
|
||||
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.plugins.register :as preg]
|
||||
|
@ -40,14 +42,22 @@
|
|||
icon))
|
||||
|
||||
(mf/defc plugin-entry
|
||||
[{:keys [index manifest on-open-plugin on-remove-plugin]}]
|
||||
[{:keys [index manifest user-can-edit on-open-plugin on-remove-plugin]}]
|
||||
|
||||
(let [{:keys [plugin-id host icon name description permissions]} manifest
|
||||
plugins-permissions-peek (deref refs/plugins-permissions-peek)
|
||||
permissions (or (get plugins-permissions-peek plugin-id)
|
||||
permissions)
|
||||
is-edition-plugin? (or (contains? permissions "content:write")
|
||||
(contains? permissions "library:write"))
|
||||
can-open? (or user-can-edit
|
||||
(not is-edition-plugin?))
|
||||
|
||||
(let [{:keys [host icon name description]} manifest
|
||||
handle-open-click
|
||||
(mf/use-callback
|
||||
(mf/deps index manifest on-open-plugin)
|
||||
(mf/deps index manifest on-open-plugin can-open?)
|
||||
(fn []
|
||||
(when on-open-plugin
|
||||
(when (and can-open? on-open-plugin)
|
||||
(on-open-plugin manifest))))
|
||||
|
||||
handle-delete-click
|
||||
|
@ -64,8 +74,14 @@
|
|||
[:div {:class (stl/css :plugin-description)}
|
||||
[:div {:class (stl/css :plugin-title)} name]
|
||||
[:div {:class (stl/css :plugin-summary)} (d/nilv description "")]]
|
||||
[:button {:class (stl/css :open-button)
|
||||
:on-click handle-open-click} (tr "workspace.plugins.button-open")]
|
||||
|
||||
|
||||
[:> button* {:class (stl/css :open-button)
|
||||
:variant "secondary"
|
||||
:on-click handle-open-click
|
||||
:title (when-not can-open? (tr "workspace.plugins.error.need-editor"))
|
||||
:disabled (not can-open?)} (tr "workspace.plugins.button-open")]
|
||||
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "workspace.plugins.remove-plugin")
|
||||
:on-click handle-delete-click
|
||||
|
@ -91,6 +107,8 @@
|
|||
error-manifest? (= :error-manifest input-status)
|
||||
error? (or error-url? error-manifest?)
|
||||
|
||||
user-can-edit? (:can-edit (deref refs/permissions))
|
||||
|
||||
handle-close-dialog
|
||||
(mf/use-callback
|
||||
(fn []
|
||||
|
@ -137,7 +155,7 @@
|
|||
::ev/origin "workspace:plugins"
|
||||
:name (:name manifest)
|
||||
:host (:host manifest)}))
|
||||
(dp/open-plugin! manifest)
|
||||
(dp/open-plugin! manifest user-can-edit?)
|
||||
(modal/hide!)))
|
||||
|
||||
handle-remove-plugin
|
||||
|
@ -204,6 +222,7 @@
|
|||
[:& plugin-entry {:key (dm/str "plugin-" idx)
|
||||
:index idx
|
||||
:manifest manifest
|
||||
:user-can-edit user-can-edit?
|
||||
:on-open-plugin handle-open-plugin
|
||||
:on-remove-plugin handle-remove-plugin}])]])]]]))
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
@include flexCenter;
|
||||
width: $s-20;
|
||||
padding: 0 0 0 $s-8;
|
||||
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--icon-foreground);
|
||||
|
@ -114,7 +115,9 @@
|
|||
}
|
||||
|
||||
.open-button {
|
||||
@extend .button-secondary;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: $s-68;
|
||||
min-width: $s-68;
|
||||
height: $s-32;
|
||||
|
|
|
@ -5859,6 +5859,10 @@ msgstr "Plugins"
|
|||
msgid "workspace.plugins.remove-plugin"
|
||||
msgstr "Remove plugin"
|
||||
|
||||
#: src/app/main/data/plugins.cljs:78
|
||||
msgid "workspace.plugins.error.need-editor"
|
||||
msgstr "You need to be an editor to use this plugin"
|
||||
|
||||
#: /src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1005
|
||||
msgid "workspace.shape.menu.add-layout"
|
||||
msgstr "Add layout"
|
||||
|
|
|
@ -5837,6 +5837,10 @@ msgstr "Extensiones"
|
|||
msgid "workspace.plugins.remove-plugin"
|
||||
msgstr "Eliminar extensión"
|
||||
|
||||
#: src/app/main/data/plugins.cljs:78
|
||||
msgid "workspace.plugins.error.need-editor"
|
||||
msgstr "Debes ser un editor para usar este plugin"
|
||||
|
||||
#: /src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1005
|
||||
msgid "workspace.shape.menu.add-layout"
|
||||
msgstr "Añadir layout"
|
||||
|
|
Loading…
Add table
Reference in a new issue