diff --git a/frontend/src/app/main/data/plugins.cljs b/frontend/src/app/main/data/plugins.cljs index 97d286040..ba27e6a0a 100644 --- a/frontend/src/app/main/data/plugins.cljs +++ b/frontend/src/app/main/data/plugins.cljs @@ -6,14 +6,24 @@ (ns app.main.data.plugins (:require - [app.common.data :as d] [app.common.data.macros :as dm] + [app.main.data.modal :as modal] [app.main.store :as st] - [app.plugins.register :as pr] + [app.plugins.register :as preg] [app.util.globals :as ug] + [app.util.http :as http] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) +(defn fetch-manifest + [plugin-url] + (->> (http/send! {:method :get + :uri plugin-url + :omit-default-headers true + :response-type :json}) + (rx/map :body) + (rx/map #(preg/parse-manifest plugin-url %)))) + (defn save-current-plugin [id] (ptk/reify ::save-current-plugin @@ -28,7 +38,7 @@ (update [_ state] (update-in state [:workspace-local :open-plugins] (fnil disj #{}) id)))) -(defn open-plugin! +(defn- load-plugin! [{:keys [plugin-id name description host code icon permissions]}] (try (st/emit! (save-current-plugin plugin-id)) @@ -48,6 +58,36 @@ (st/emit! (remove-current-plugin plugin-id)) (.error js/console "Error" e)))) +(defn open-plugin! + [{:keys [url] :as manifest}] + (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]))] + (cond + (not= (:permissions new-manifest) (:permissions manifest)) + (modal/show! + :plugin-permissions-update + {:plugin new-manifest + :on-accept + #(do + (preg/install-plugin! new-manifest) + (load-plugin! new-manifest))}) + + (not= new-manifest manifest) + (do (preg/install-plugin! new-manifest) + (load-plugin! manifest)) + :else + (load-plugin! manifest)))) + (fn [] + ;; Error fetching the manifest we'll load the plugin with the + ;; old manifest + (load-plugin! manifest)))) + (load-plugin! manifest))) + (defn close-plugin! [{:keys [plugin-id]}] (try @@ -62,7 +102,7 @@ (effect [_ state _] (let [ids (dm/get-in state [:workspace-local :open-plugins])] (doseq [id ids] - (close-plugin! (pr/get-plugin id))))))) + (close-plugin! (preg/get-plugin id))))))) (defn delay-open-plugin [plugin] @@ -77,5 +117,5 @@ ptk/WatchEvent (watch [_ state _] (when-let [pid (::open-plugin state)] - (open-plugin! (pr/get-plugin pid)) + (open-plugin! (preg/get-plugin pid)) (rx/of #(dissoc % ::open-plugin)))))) diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index 277690ae9..a15822104 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -33,7 +33,6 @@ [app.main.ui.workspace.plugins] [app.plugins.register :as preg] [app.util.dom :as dom] - [app.util.http :as http] [app.util.keyboard :as kbd] [app.util.object :as obj] [app.util.router :as rt] @@ -202,19 +201,14 @@ (mf/with-layout-effect [plugin-url team-id project-id] (when plugin-url - (->> (http/send! {:method :get - :uri plugin-url - :omit-default-headers true - :response-type :json}) - (rx/map :body) + (->> (dp/fetch-manifest plugin-url) (rx/subs! - (fn [body] - (if-let [plugin (preg/parse-manifest plugin-url body)] + (fn [plugin] + (if plugin (do (st/emit! (ptk/event ::ev/event {::ev/name "install-plugin" :name (:name plugin) :url plugin-url})) (open-permissions-dialog plugin)) (st/emit! (notif/error "Cannot parser the plugin manifest")))) - (fn [_] (st/emit! (notif/error "The plugin URL is incorrect"))))))))) diff --git a/frontend/src/app/main/ui/workspace/plugins.cljs b/frontend/src/app/main/ui/workspace/plugins.cljs index ff0a18e78..cecc22bf6 100644 --- a/frontend/src/app/main/ui/workspace/plugins.cljs +++ b/frontend/src/app/main/ui/workspace/plugins.cljs @@ -20,7 +20,6 @@ [app.plugins.register :as preg] [app.util.avatars :as avatars] [app.util.dom :as dom] - [app.util.http :as http] [app.util.i18n :as i18n :refer [tr]] [beicon.v2.core :as rx] [cuerdas.core :as str] @@ -96,15 +95,11 @@ (mf/deps plugins-state plugin-url) (fn [] (reset! fetching-manifest? true) - (->> (http/send! {:method :get - :uri plugin-url - :omit-default-headers true - :response-type :json}) - (rx/map :body) + (->> (dp/fetch-manifest plugin-url) (rx/subs! - (fn [body] + (fn [plugin] (reset! fetching-manifest? false) - (if-let [plugin (preg/parse-manifest plugin-url body)] + (if plugin (do (st/emit! (ptk/event ::ev/event {::ev/name "install-plugin" :name (:name plugin) :url plugin-url})) (modal/show! @@ -118,7 +113,8 @@ (reset! plugin-url* "")) ;; Cannot get the manifest (reset! input-status* :error-manifest))) - (fn [_] + (fn [err] + (.error js/console err) (reset! fetching-manifest? false) (reset! input-status* :error-url)))))) @@ -199,6 +195,62 @@ :on-open-plugin handle-open-plugin :on-remove-plugin handle-remove-plugin}])]])]]])) +(mf/defc plugins-permission-list + [{:keys [permissions]}] + [:div {:class (stl/css :permissions-list)} + (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")]]) + + (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")]]) + + (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-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-read")]]) + + (cond + (contains? permissions "comment:write") + [:div {:class (stl/css :permissions-list-entry)} + i/oauth-1 + [:p {:class (stl/css :permissions-list-text)} + (tr "workspace.plugins.permissions.comment-write")]] + + (contains? permissions "comment:read") + [:div {:class (stl/css :permissions-list-entry)} + i/oauth-1 + [:p {:class (stl/css :permissions-list-text)} + (tr "workspace.plugins.permissions.comment-read")]]) + + (cond + (contains? permissions "allow:downloads") + [:div {:class (stl/css :permissions-list-entry)} + i/oauth-1 + [:p {:class (stl/css :permissions-list-text)} + (tr "workspace.plugins.permissions.allow-download")]])]) + (mf/defc plugins-permissions-dialog {::mf/register modal/components ::mf/register-as :plugin-permissions} @@ -233,59 +285,7 @@ [:div {:class (stl/css :modal-title)} (tr "workspace.plugins.permissions.title" (str/upper (:name plugin)))] [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :permissions-list)} - (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")]]) - - (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")]]) - - (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-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-read")]]) - - (cond - (contains? permissions "comment:write") - [:div {:class (stl/css :permissions-list-entry)} - i/oauth-1 - [:p {:class (stl/css :permissions-list-text)} - (tr "workspace.plugins.permissions.comment-write")]] - - (contains? permissions "comment:read") - [:div {:class (stl/css :permissions-list-entry)} - i/oauth-1 - [:p {:class (stl/css :permissions-list-text)} - (tr "workspace.plugins.permissions.comment-read")]]) - - (cond - (contains? permissions "allow:downloads") - [:div {:class (stl/css :permissions-list-entry)} - i/oauth-1 - [:p {:class (stl/css :permissions-list-text)} - (tr "workspace.plugins.permissions.allow-download")]])] + [:& plugins-permission-list {:permissions permissions}] [:div {:class (stl/css :permissions-disclaimer)} (tr "workspace.plugins.permissions.disclaimer")]] @@ -305,6 +305,60 @@ :on-click handle-accept-dialog}]]]]])) +(mf/defc plugins-permissions-updated-dialog + {::mf/register modal/components + ::mf/register-as :plugin-permissions-update} + [{:keys [plugin on-accept on-close]}] + + (let [{:keys [host permissions]} plugin + permissions (set permissions) + + handle-accept-dialog + (mf/use-callback + (fn [event] + (dom/prevent-default event) + (st/emit! (ptk/event ::ev/event {::ev/name "allow-plugin-permissions" + :host host + :permissions (->> permissions (str/join ", "))}) + (modal/hide)) + (when on-accept (on-accept)))) + + handle-close-dialog + (mf/use-callback + (fn [event] + (dom/prevent-default event) + (st/emit! (ptk/event ::ev/event {::ev/name "reject-plugin-permissions" + :host host + :permissions (->> permissions (str/join ", "))}) + (modal/hide)) + (when on-close (on-close))))] + + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-dialog :plugin-permissions)} + [:button {:class (stl/css :close-btn) :on-click handle-close-dialog} close-icon] + [:div {:class (stl/css :modal-title)} + (tr "workspace.plugins.permissions-update.title" (str/upper (:name plugin)))] + + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-paragraph)} + (tr "workspace.plugins.permissions-update.warning")] + [:& plugins-permission-list {:permissions permissions}]] + + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + [:input + {:class (stl/css :cancel-button :button-expand) + :type "button" + :value (tr "ds.confirm-cancel") + :on-click handle-close-dialog}] + + [:input + {:class (stl/css :primary-button :button-expand) + :type "button" + :value (tr "ds.confirm-allow") + :on-click handle-accept-dialog}]]]]])) + + (mf/defc plugins-try-out-dialog {::mf/register modal/components ::mf/register-as :plugin-try-out} diff --git a/frontend/src/app/main/ui/workspace/plugins.scss b/frontend/src/app/main/ui/workspace/plugins.scss index bc63bbe1f..ba736acf8 100644 --- a/frontend/src/app/main/ui/workspace/plugins.scss +++ b/frontend/src/app/main/ui/workspace/plugins.scss @@ -76,6 +76,11 @@ color: var(--color-foreground-secondary); } +.modal-paragraph { + font-size: $fs-14; + color: var(--color-foreground-primary); +} + .primary-button { @extend .button-primary; @include headlineSmallTypography; diff --git a/frontend/src/app/plugins/register.cljs b/frontend/src/app/plugins/register.cljs index 19e98a805..f8e3e03be 100644 --- a/frontend/src/app/plugins/register.cljs +++ b/frontend/src/app/plugins/register.cljs @@ -64,6 +64,7 @@ manifest (d/without-nils {:plugin-id plugin-id + :url plugin-url :name name :description desc :host origin diff --git a/frontend/translations/en.po b/frontend/translations/en.po index a87e94f7c..b0b931a05 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5610,6 +5610,12 @@ msgstr "'%s' PLUGIN WANTS ACCESS TO:" msgid "workspace.plugins.permissions.user-read" msgstr "Read the profile information of the current user." +msgid "workspace.plugins.permissions-update.title" +msgstr "UPDATE THIS PLUGIN" + +msgid "workspace.plugins.permissions-update.warning" +msgstr "The plugin has been modified since you last opened it. It now also wants to access:" + msgid "workspace.plugins.try-out.title" msgstr "'%s' PLUGIN IS INSTALLED FOR YOUR USER!" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 54cbc1a11..7400fd0b9 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -5594,6 +5594,12 @@ msgstr "LA EXTENSIÓN '%s' SOLICITA PERMISO PARA ACCEDER:" msgid "workspace.plugins.permissions.user-read" msgstr "Leer la información del usuario actual." +msgid "workspace.plugins.permissions-update.title" +msgstr "EXTENSIÓN ACTUALIZADA" + +msgid "workspace.plugins.permissions-update.warning" +msgstr "La extensión ha cambiado desde la última vez que la abriste. Ahora quiere acceder a:" + msgid "workspace.plugins.try-out.title" msgstr "¡LA EXTENSIÓN '%s' HA SIDO INSTALADA PARA TU USUARIO!"