From d6da8afdce343bb853994c27b88fa13190437848 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 18 Oct 2024 16:23:24 +0200 Subject: [PATCH] :sparkles: Add improved abstraction for team permissions Relevant changes: - replace user-viewer? with can-edit removing many double negations on the code - always use team permissions making the permissions access uniform around all the code - expose team permissions to ui tree through ctx/team-permissions context --- frontend/src/app/main/data/changes.cljs | 13 +- frontend/src/app/main/data/common.cljs | 40 +++--- frontend/src/app/main/data/dashboard.cljs | 19 ++- frontend/src/app/main/data/users.cljs | 1 + .../src/app/main/data/workspace/common.cljs | 2 +- .../main/data/workspace/notifications.cljs | 34 +++-- .../app/main/data/workspace/shortcuts.cljs | 12 +- .../main/data/workspace/text/shortcuts.cljs | 27 ++-- frontend/src/app/main/refs.cljs | 6 + frontend/src/app/main/ui/context.cljs | 2 +- frontend/src/app/main/ui/dashboard.cljs | 82 +++++++------ .../src/app/main/ui/dashboard/file_menu.cljs | 27 ++-- frontend/src/app/main/ui/dashboard/files.cljs | 35 +++--- frontend/src/app/main/ui/dashboard/fonts.cljs | 40 +++--- frontend/src/app/main/ui/dashboard/grid.cljs | 44 +++---- .../src/app/main/ui/dashboard/libraries.cljs | 6 +- .../app/main/ui/dashboard/placeholder.cljs | 15 ++- .../src/app/main/ui/dashboard/projects.cljs | 38 +++--- frontend/src/app/main/ui/dashboard/team.cljs | 62 +++++----- .../app/main/ui/onboarding/team_choice.cljs | 5 +- frontend/src/app/main/ui/workspace.cljs | 10 +- .../app/main/ui/workspace/context_menu.cljs | 48 ++++---- .../src/app/main/ui/workspace/main_menu.cljs | 116 +++++++++--------- .../main/ui/workspace/sidebar/options.cljs | 11 +- .../main/ui/workspace/sidebar/sitemap.cljs | 27 ++-- .../src/app/main/ui/workspace/viewport.cljs | 26 ++-- .../main/ui/workspace/viewport/actions.cljs | 50 ++++---- .../test/frontend_tests/helpers/pages.cljs | 2 +- .../test/frontend_tests/helpers/state.cljs | 3 +- 29 files changed, 412 insertions(+), 391 deletions(-) diff --git a/frontend/src/app/main/data/changes.cljs b/frontend/src/app/main/data/changes.cljs index 0f6454141..e10063fb0 100644 --- a/frontend/src/app/main/data/changes.cljs +++ b/frontend/src/app/main/data/changes.cljs @@ -178,15 +178,14 @@ (ptk/reify ::commit-changes ptk/WatchEvent (watch [_ state _] - (let [file-id (or file-id (:current-file-id state)) - uchg (vec undo-changes) - rchg (vec redo-changes) - features (features/get-team-enabled-features state) - user-viewer? (not (dm/get-in state [:workspace-file :permissions :can-edit]))] + (let [file-id (or file-id (:current-file-id state)) + uchg (vec undo-changes) + rchg (vec redo-changes) + features (features/get-team-enabled-features state) + permissions (:permissions state)] ;; Prevent commit changes by a viewer team member (it really should never happen) - (if user-viewer? - (rx/empty) + (when (:can-edit permissions) (rx/of (-> params (assoc :undo-group undo-group) (assoc :features features) diff --git a/frontend/src/app/main/data/common.cljs b/frontend/src/app/main/data/common.cljs index 64f3cd14f..576e6c656 100644 --- a/frontend/src/app/main/data/common.cljs +++ b/frontend/src/app/main/data/common.cljs @@ -7,10 +7,11 @@ (ns app.main.data.common "A general purpose events." (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.common.schema :as sm] [app.common.types.components-list :as ctkl] - [app.common.types.team :as tt] + [app.common.types.team :as ctt] [app.config :as cf] [app.main.data.modal :as modal] [app.main.data.notifications :as ntf] @@ -196,7 +197,7 @@ (rx/tap on-success) (rx/catch on-error)))))) -(defn- change-role-msg +(defn- get-change-role-msg [role] (case role :viewer (tr "dashboard.permissions-change.viewer") @@ -204,26 +205,23 @@ :admin (tr "dashboard.permissions-change.admin") :owner (tr "dashboard.permissions-change.owner"))) - -(defn change-team-permissions - [{:keys [team-id role workspace?]}] +(defn change-team-role + [{:keys [team-id role]}] (dm/assert! (uuid? team-id)) - (dm/assert! (contains? tt/valid-roles role)) - (ptk/reify ::change-team-permissions + (dm/assert! (contains? ctt/valid-roles role)) + + (ptk/reify ::change-team-role ptk/WatchEvent (watch [_ _ _] - (rx/of (ntf/info (change-role-msg role)))) + (rx/of (ntf/info (get-change-role-msg role)))) ptk/UpdateEvent (update [_ state] - (let [route (if workspace? - [:workspace-file :permissions] - [:teams team-id :permissions])] - (update-in state route - (fn [permissions] - (merge permissions (get tt/permissions-for-role role)))))))) - - + (let [permissions (get ctt/permissions-for-role role)] + (-> state + (update :permissions merge permissions) + (update-in [:team :permissions] merge permissions) + (d/update-in-when [:teams team-id :permissions] merge permissions)))))) (defn team-membership-change [{:keys [team-id team-name change]}] @@ -232,12 +230,12 @@ ptk/WatchEvent (watch [_ state _] (when (= :removed change) - (let [msg (tr "dashboard.removed-from-team" team-name)] - + (let [message (tr "dashboard.removed-from-team" team-name) + profile (:profile state)] (rx/concat - (rx/of (rt/nav :dashboard-projects {:team-id (get-in state [:profile :default-team-id])})) - (->> (rx/of (ntf/info msg)) - ;; Delay so the navigation can finish + (rx/of (rt/nav :dashboard-projects {:team-id (:default-team-id profile)})) + (->> (rx/of (ntf/info message)) + ;; Delay so the navigation can finish (rx/delay 250)))))))) diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs index 03ccc2ec7..6a1ca65fe 100644 --- a/frontend/src/app/main/data/dashboard.cljs +++ b/frontend/src/app/main/data/dashboard.cljs @@ -12,7 +12,7 @@ [app.common.files.helpers :as cfh] [app.common.logging :as log] [app.common.schema :as sm] - [app.common.types.team :as tt] + [app.common.types.team :as ctt] [app.common.uri :as u] [app.common.uuid :as uuid] [app.config :as cf] @@ -482,7 +482,7 @@ (defn update-team-member-role [{:keys [role member-id] :as params}] (dm/assert! (uuid? member-id)) - (dm/assert! (contains? tt/valid-roles role)) + (dm/assert! (contains? ctt/valid-roles role)) (ptk/reify ::update-team-member-role ptk/WatchEvent @@ -605,7 +605,7 @@ (sm/check-email! email)) (dm/assert! (uuid? team-id)) - (dm/assert! (contains? tt/valid-roles role)) + (dm/assert! (contains? ctt/valid-roles role)) (ptk/reify ::update-team-invitation-role IDeref @@ -1211,19 +1211,18 @@ ;; Notifications ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defn- handle-change-team-permissions-dashboard - [msg] - (ptk/reify ::handle-change-team-permissions-dashboard +(defn- handle-change-team-role + [params] + (ptk/reify ::handle-change-team-role ptk/WatchEvent (watch [_ _ _] - (rx/of (dc/change-team-permissions (assoc msg :workspace? false)) + (rx/of (dc/change-team-role params) (modal/hide))))) (defn- process-message [{:keys [type] :as msg}] (case type :notification (dc/handle-notification msg) - :team-role-change (handle-change-team-permissions-dashboard msg) + :team-role-change (handle-change-team-role msg) :team-membership-change (dc/team-membership-change msg) - nil)) \ No newline at end of file + nil)) diff --git a/frontend/src/app/main/data/users.cljs b/frontend/src/app/main/data/users.cljs index 1c729ac74..4ec142222 100644 --- a/frontend/src/app/main/data/users.cljs +++ b/frontend/src/app/main/data/users.cljs @@ -97,6 +97,7 @@ (update [_ state] (-> state (assoc :team team) + (assoc :permissions (:permissions team)) (assoc :current-team-id (:id team)))) ptk/WatchEvent diff --git a/frontend/src/app/main/data/workspace/common.cljs b/frontend/src/app/main/data/workspace/common.cljs index 3902252c5..1cc6ecad0 100644 --- a/frontend/src/app/main/data/workspace/common.cljs +++ b/frontend/src/app/main/data/workspace/common.cljs @@ -68,7 +68,7 @@ (ptk/reify ::set-workspace-read-only ptk/UpdateEvent (update [_ state] - (assoc-in state [:workspace-global :read-only?] read-only?)) + (update state :workspace-global assoc :read-only? read-only?)) ptk/WatchEvent (watch [_ _ _] diff --git a/frontend/src/app/main/data/workspace/notifications.cljs b/frontend/src/app/main/data/workspace/notifications.cljs index 449c26e6b..5a82818a1 100644 --- a/frontend/src/app/main/data/workspace/notifications.cljs +++ b/frontend/src/app/main/data/workspace/notifications.cljs @@ -97,26 +97,22 @@ (rx/concat stream (rx/of (dws/send endmsg))))))) - -(defn- handle-change-team-permissions +(defn- handle-change-team-role [{:keys [role] :as msg}] - (ptk/reify ::handle-change-team-permissions + (ptk/reify ::handle-change-team-role ptk/WatchEvent (watch [_ _ _] - (let [viewer? (= :viewer role)] - - (rx/concat - (rx/of :interrupt - (dwe/clear-edition-mode) - (dwc/set-workspace-read-only false)) - (->> (rx/of (dc/change-team-permissions msg)) - ;; Delay so anything that launched :interrupt can finish - (rx/delay 100)) - (if viewer? - (rx/of (modal/hide) - (dwly/set-options-mode :inspect)) - (rx/of (dwly/set-options-mode :design)))))))) - + (rx/concat + (rx/of :interrupt + (dwe/clear-edition-mode) + (dwc/set-workspace-read-only false)) + (->> (rx/of (dc/change-team-role msg)) + ;; Delay so anything that launched :interrupt can finish + (rx/delay 100)) + (if (= :viewer role) + (rx/of (modal/hide) + (dwly/set-options-mode :inspect)) + (rx/of (dwly/set-options-mode :design))))))) (defn- process-message [{:keys [type] :as msg}] @@ -129,7 +125,7 @@ :file-change (handle-file-change msg) :library-change (handle-library-change msg) :notification (dc/handle-notification msg) - :team-role-change (handle-change-team-permissions (assoc msg :workspace? true)) + :team-role-change (handle-change-team-role msg) :team-membership-change (dc/team-membership-change msg) nil)) @@ -284,4 +280,4 @@ (watch [_ state _] (when (contains? (:workspace-libraries state) file-id) (rx/of (dwl/ext-library-changed file-id modified-at revn changes) - (dwl/notify-sync-file file-id)))))) \ No newline at end of file + (dwl/notify-sync-file file-id)))))) diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs index 694143e40..1bf35f699 100644 --- a/frontend/src/app/main/data/workspace/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/shortcuts.cljs @@ -37,18 +37,16 @@ ;; Shortcuts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn toggle-layout-flag +(defn- toggle-layout-flag [flag] (-> (dw/toggle-layout-flag flag) (vary-meta assoc ::ev/origin "workspace-shortcuts"))) -(defn emit-when-no-readonly +(defn- emit-when-no-readonly [& events] - (let [file (deref refs/workspace-file) - user-viewer? (not (dm/get-in file [:permissions :can-edit])) - read-only? (or (deref refs/workspace-read-only?) - user-viewer?)] - (when-not read-only? + (let [can-edit? (:can-edit (deref refs/permissions)) + read-only? (deref refs/workspace-read-only?)] + (when (and can-edit? (not read-only?)) (run! st/emit! events)))) (def esc-pressed diff --git a/frontend/src/app/main/data/workspace/text/shortcuts.cljs b/frontend/src/app/main/data/workspace/text/shortcuts.cljs index 446aa015b..dc5272c29 100644 --- a/frontend/src/app/main/data/workspace/text/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/text/shortcuts.cljs @@ -7,7 +7,7 @@ (ns app.main.data.workspace.text.shortcuts (:require [app.common.data :as d] - [app.common.data.macros :as dm] + [app.common.files.helpers :as cfh] [app.common.text :as txt] [app.main.data.shortcuts :as ds] [app.main.data.workspace.texts :as dwt] @@ -189,17 +189,20 @@ props))) (defn- update-attrs-when-no-readonly [props] - (let [undo-id (js/Symbol) - file (deref refs/workspace-file) - user-viewer? (not (dm/get-in file [:permissions :can-edit])) - read-only? (or (deref refs/workspace-read-only?) - user-viewer?) - shapes-with-children (deref refs/selected-shapes-with-children) - text-shapes (filter #(= (:type %) :text) shapes-with-children) - props (if (> (count text-shapes) 1) - (blend-props text-shapes props) - props)] - (when (and (not read-only?) text-shapes) + (let [undo-id (js/Symbol) + + can-edit? (:can-edit (deref refs/permissions)) + read-only? (deref refs/workspace-read-only?) + + text-shapes (->> (deref refs/selected-shapes-with-children) + (filter cfh/text-shape?) + (not-empty)) + + props (if (> (count text-shapes) 1) + (blend-props text-shapes props) + props)] + + (when (and can-edit? (not read-only?) text-shapes) (st/emit! (dwu/start-undo-transaction undo-id)) (run! #(update-attrs % props) text-shapes) (st/emit! (dwu/commit-undo-transaction undo-id))))) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index a755dc9fe..5b6c2bdea 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -27,6 +27,12 @@ (def profile (l/derived :profile st/state)) +(def team + (l/derived :team st/state)) + +(def permissions + (l/derived :permissions st/state)) + (def teams (l/derived :teams st/state)) diff --git a/frontend/src/app/main/ui/context.cljs b/frontend/src/app/main/ui/context.cljs index 9323171ce..5afe7987f 100644 --- a/frontend/src/app/main/ui/context.cljs +++ b/frontend/src/app/main/ui/context.cljs @@ -32,4 +32,4 @@ (def is-component? (mf/create-context false)) (def sidebar (mf/create-context nil)) -(def user-viewer? (mf/create-context nil)) +(def team-permissions (mf/create-context nil)) diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index 37e023cc0..429987f90 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -61,14 +61,15 @@ (mf/defc dashboard-content [{:keys [team projects project section search-term profile invite-email] :as props}] - (let [container (mf/use-ref) - content-width (mf/use-state 0) - project-id (:id project) - team-id (:id team) - you-viewer? (not (dm/get-in team [:permissions :can-edit])) + (let [container (mf/use-ref) + content-width (mf/use-state 0) + project-id (:id project) + team-id (:id team) - dashboard-local (mf/deref refs/dashboard-local) - file-menu-open? (:menu-open dashboard-local) + permissions (:permissions team) + + dashboard-local (mf/deref refs/dashboard-local) + file-menu-open? (:menu-open dashboard-local) default-project-id (mf/with-memo [projects] @@ -87,8 +88,9 @@ (mf/use-fn #(st/emit! (dd/clear-selected-files))) - show-templates (and (contains? cf/flags :dashboard-templates-section) - (not you-viewer?))] + show-templates + (and (contains? cf/flags :dashboard-templates-section) + (not (:can-edit permissions)))] (mf/with-effect [] (let [key1 (events/listen js/window "resize" on-resize)] @@ -117,7 +119,7 @@ :content-width @content-width}])] :dashboard-fonts - [:& fonts-page {:team team :you-viewer? you-viewer?}] + [:& fonts-page {:team team}] :dashboard-font-providers [:& font-providers-page {:team team}] @@ -125,7 +127,7 @@ :dashboard-files (when project [:* - [:& files-section {:team team :project project :you-viewer? you-viewer?}] + [:& files-section {:team team :project project}] (when show-templates [:& templates-section {:profile profile :team-id team-id @@ -138,7 +140,7 @@ :search-term search-term}] :dashboard-libraries - [:& libraries-page {:team team :you-viewer? you-viewer?}] + [:& libraries-page {:team team}] :dashboard-team-members [:& team-members-page {:team team :profile profile :invite-email invite-email}] @@ -231,8 +233,7 @@ invite-email (-> route :query-params :invite-email) - teams (mf/deref refs/teams) - team (get teams team-id) + team (mf/deref refs/team) projects (mf/deref refs/dashboard-projects) project (get projects project-id) @@ -261,29 +262,30 @@ [:& (mf/provider ctx/current-team-id) {:value team-id} [:& (mf/provider ctx/current-project-id) {:value project-id} - ;; NOTE: dashboard events and other related functions assumes - ;; that the team is a implicit context variable that is - ;; available using react context or accessing - ;; the :current-team-id on the state. We set the key to the - ;; team-id because we want to completely refresh all the - ;; components on team change. Many components assumes that the - ;; team is already set so don't put the team into mf/deps. - (when (and team initialized?) - [:main {:class (stl/css :dashboard) - :key (:id team)} - [:& sidebar - {:team team - :projects projects - :project project - :profile profile - :section section - :search-term search-term}] - (when (and team profile (seq projects)) - [:& dashboard-content - {:projects projects - :profile profile - :project project - :section section - :search-term search-term - :team team - :invite-email invite-email}])])]])) + [:& (mf/provider ctx/team-permissions) {:value (:permissions team)} + ;; NOTE: dashboard events and other related functions assumes + ;; that the team is a implicit context variable that is + ;; available using react context or accessing + ;; the :current-team-id on the state. We set the key to the + ;; team-id because we want to completely refresh all the + ;; components on team change. Many components assumes that the + ;; team is already set so don't put the team into mf/deps. + (when (and team initialized?) + [:main {:class (stl/css :dashboard) + :key (:id team)} + [:& sidebar + {:team team + :projects projects + :project project + :profile profile + :section section + :search-term search-term}] + (when (and team profile (seq projects)) + [:& dashboard-content + {:projects projects + :profile profile + :project project + :section section + :search-term search-term + :team team + :invite-email invite-email}])])]]])) diff --git a/frontend/src/app/main/ui/dashboard/file_menu.cljs b/frontend/src/app/main/ui/dashboard/file_menu.cljs index 7d133dbc3..bd66900d2 100644 --- a/frontend/src/app/main/ui/dashboard/file_menu.cljs +++ b/frontend/src/app/main/ui/dashboard/file_menu.cljs @@ -57,7 +57,7 @@ (mf/defc file-menu {::mf/wrap-props false} - [{:keys [files show? on-edit on-menu-close top left navigate? origin parent-id you-viewer?]}] + [{:keys [files show? on-edit on-menu-close top left navigate? origin parent-id can-edit]}] (assert (seq files) "missing `files` prop") (assert (boolean? show?) "missing `show?` prop") (assert (fn? on-edit) "missing `on-edit` prop") @@ -245,13 +245,12 @@ options (if multi? - [(when-not you-viewer? + [(when can-edit {:name (tr "dashboard.duplicate-multi" file-count) :id "duplicate-multi" :handler on-duplicate}) - (when (and (or (seq current-projects) (seq other-teams)) - (not you-viewer?)) + (when (and (or (seq current-projects) (seq other-teams)) can-edit) {:name (tr "dashboard.move-to-multi" file-count) :id "file-move-multi" :options sub-options}) @@ -269,14 +268,12 @@ :id "file-standard-export-multi" :handler on-export-standard-files} - (when (and (:is-shared file) - (not you-viewer?)) + (when (and (:is-shared file) can-edit) {:name (tr "labels.unpublish-multi-files" file-count) :id "file-unpublish-multi" :handler on-del-shared}) - (when (and (not is-lib-page?) - (not you-viewer?)) + (when (and (not is-lib-page?) can-edit) {:name :separator} {:name (tr "labels.delete-multi-files" file-count) :id "file-delete-multi" @@ -285,14 +282,12 @@ [{:name (tr "dashboard.open-in-new-tab") :id "file-open-new-tab" :handler on-new-tab} - (when (and (not is-search-page?) - (not you-viewer?)) + (when (and (not is-search-page?) can-edit) {:name (tr "labels.rename") :id "file-rename" :handler on-edit}) - (when (and (not is-search-page?) - (not you-viewer?)) + (when (and (not is-search-page?) can-edit) {:name (tr "dashboard.duplicate") :id "file-duplicate" :handler on-duplicate}) @@ -300,13 +295,13 @@ (when (and (not is-lib-page?) (not is-search-page?) (or (seq current-projects) (seq other-teams)) - (not you-viewer?)) + can-edit) {:name (tr "dashboard.move-to") :id "file-move-to" :options sub-options}) (when (and (not is-search-page?) - (not you-viewer?)) + can-edit) (if (:is-shared file) {:name (tr "dashboard.unpublish-shared") :id "file-del-shared" @@ -330,10 +325,10 @@ :id "download-standard-file" :handler on-export-standard-files} - (when (and (not is-lib-page?) (not is-search-page?) (not you-viewer?)) + (when (and (not is-lib-page?) (not is-search-page?) can-edit) {:name :separator}) - (when (and (not is-lib-page?) (not is-search-page?) (not you-viewer?)) + (when (and (not is-lib-page?) (not is-search-page?) can-edit) {:name (tr "labels.delete") :id "file-delete" :handler on-delete})])] diff --git a/frontend/src/app/main/ui/dashboard/files.cljs b/frontend/src/app/main/ui/dashboard/files.cljs index 13ea519c6..d6d2b76c5 100644 --- a/frontend/src/app/main/ui/dashboard/files.cljs +++ b/frontend/src/app/main/ui/dashboard/files.cljs @@ -28,8 +28,10 @@ (def ^:private menu-icon (i/icon-xref :menu (stl/css :menu-icon))) -(mf/defc header - [{:keys [project create-fn you-viewer?] :as props}] +(mf/defc header* + {::mf/props :obj + ::mf/private true} + [{:keys [project create-fn can-edit]}] (let [local (mf/use-state {:menu-open false :edition false}) @@ -72,8 +74,7 @@ [:div#dashboard-drafts-title {:class (stl/css :dashboard-title)} [:h1 (tr "labels.drafts")]] - (if (and (:edition @local) - (not you-viewer?)) + (if (and (:edition @local) can-edit) [:& inline-edition {:content (:name project) :on-end (fn [name] @@ -89,7 +90,7 @@ (:name project)]])) [:div {:class (stl/css :dashboard-header-actions)} - (when-not you-viewer? + (when ^boolean can-edit [:a {:class (stl/css :btn-secondary :btn-small :new-file) :tab-index "0" :on-click on-create-click @@ -106,7 +107,7 @@ :on-click toggle-pin :on-key-down (fn [event] (when (kbd/enter? event) (toggle-pin event)))}]) - (when-not you-viewer? + (when ^boolean can-edit [:div {:class (stl/css :icon) :tab-index "0" :on-click on-menu-click @@ -116,7 +117,7 @@ (on-menu-click event)))} menu-icon]) - (when-not you-viewer? + (when ^boolean can-edit [:& project-menu {:project project :show? (:menu-open @local) :left (- (:x (:menu-pos @local)) 180) @@ -126,9 +127,11 @@ :on-import on-import}])]])) (mf/defc files-section - [{:keys [project team you-viewer?] :as props}] - (let [files-map (mf/deref refs/dashboard-files) - project-id (:id project) + {::mf/props :obj} + [{:keys [project team]}] + (let [files-map (mf/deref refs/dashboard-files) + can-edit? (-> team :permissions :can-edit) + project-id (:id project) is-draft-proyect (:is-default project) [rowref limit] (hooks/use-dynamic-grid-item-width) @@ -139,7 +142,7 @@ (sort-by :modified-at) (reverse))) file-count (or (count files) 0) - empty-state-viewer (and you-viewer? + empty-state-viewer (and (not can-edit?) (= 0 file-count)) on-file-created @@ -171,10 +174,10 @@ (dd/clear-selected-files))) [:* - [:& header {:team team - :project project - :you-viewer? you-viewer? - :create-fn create-file}] + [:> header* {:team team + :can-edit can-edit? + :project project + :create-fn create-file}] [:section {:class (stl/css :dashboard-container :no-bg) :ref rowref} (if empty-state-viewer @@ -188,7 +191,7 @@ (tr "dashboard.empty-placeholder-files-subtitle"))}] [:& grid {:project project :files files - :you-viewer? you-viewer? + :can-edit can-edit? :origin :files :create-fn create-file :limit limit}])]])) diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs index 1b6b87ad0..fecf68eb0 100644 --- a/frontend/src/app/main/ui/dashboard/fonts.cljs +++ b/frontend/src/app/main/ui/dashboard/fonts.cljs @@ -269,7 +269,7 @@ {::mf/props :obj ::mf/private true ::mf/memo true} - [{:keys [font-id variants you-viewer?]}] + [{:keys [font-id variants can-edit]}] (let [font (first variants) menu-open* (mf/use-state false) @@ -361,11 +361,11 @@ [:div {:class (stl/css :table-field :variants)} (for [{:keys [id] :as item} variants] [:div {:class (stl/css-case :variant true - :inhert-variant you-viewer?) + :inhert-variant (not can-edit)) :key (dm/str id)} [:span {:class (stl/css :label)} [:& font-variant-display-name {:variant item}]] - (when-not you-viewer? + (when can-edit [:span {:class (stl/css :icon :close) :data-id (dm/str id) @@ -384,7 +384,7 @@ :on-click on-cancel} i/close]] - (when-not you-viewer? + (when can-edit [:div {:class (stl/css :table-field :options)} [:span {:class (stl/css :icon) :on-click on-menu-open} @@ -397,7 +397,7 @@ :on-edit on-edit}]]))])) (mf/defc installed-fonts - [{:keys [fonts you-viewer?] :as props}] + [{:keys [fonts can-edit] :as props}] (let [sterm (mf/use-state "") matches? @@ -426,7 +426,7 @@ (group-by :font-id))] [:& installed-font {:key (dm/str font-id "-installed") :font-id font-id - :you-viewer? you-viewer? + :can-edit can-edit :variants variants}])] (nil? fonts) @@ -435,27 +435,33 @@ [:div {:class (stl/css :label)} (tr "dashboard.loading-fonts")]] :else - (if you-viewer? - [:> empty-placeholder* {:title (tr "dashboard.fonts.empty-placeholder-viewer") - :subtitle (tr "dashboard.fonts.empty-placeholder-viewer-sub") - :type 2}] - + (if ^boolean can-edit [:div {:class (stl/css :fonts-placeholder)} [:div {:class (stl/css :icon)} i/text] - [:div {:class (stl/css :label)} (tr "dashboard.fonts.empty-placeholder")]]))])) + [:div {:class (stl/css :label)} (tr "dashboard.fonts.empty-placeholder")]] + + [:> empty-placeholder* + {:title (tr "dashboard.fonts.empty-placeholder-viewer") + :subtitle (tr "dashboard.fonts.empty-placeholder-viewer-sub") + :type 2}]))])) + (mf/defc fonts-page - [{:keys [team you-viewer?] :as props}] - (let [fonts (mf/deref refs/dashboard-fonts)] + {::mf/props :obj} + [{:keys [team]}] + (let [fonts (mf/deref refs/dashboard-fonts) + permissions (:permissions team) + can-edit (:can-edit permissions)] [:* [:& header {:team team :section :fonts}] [:section {:class (stl/css :dashboard-container :dashboard-fonts)} - (when-not you-viewer? + (when ^boolean can-edit [:& uploaded-fonts {:team team :installed-fonts fonts}]) - [:& installed-fonts {:team team :fonts fonts :you-viewer? you-viewer?}]]])) + [:& installed-fonts {:team team :fonts fonts :can-edit can-edit}]]])) (mf/defc font-providers-page - [{:keys [team] :as props}] + {::mf/props :obj} + [{:keys [team]}] [:* [:& header {:team team :section :providers}] [:section {:class (stl/css :dashboard-container)} diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 9ad507f68..e03352342 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -73,7 +73,7 @@ (mf/defc grid-item-thumbnail {::mf/wrap-props false} - [{:keys [file-id revn thumbnail-id background-color you-viewer?]}] + [{:keys [file-id revn thumbnail-id background-color can-edit]}] (let [container (mf/use-ref) visible? (h/use-visible container :once? true)] @@ -94,12 +94,12 @@ (when visible? (if thumbnail-id [:img {:class (stl/css :grid-item-thumbnail-image) - :draggable (dm/str (not you-viewer?)) + :draggable (dm/str can-edit) :src (cf/resolve-media thumbnail-id) :loading "lazy" :decoding "async"}] [:> loader* {:class (stl/css :grid-loader) - :draggable (dm/str (not you-viewer?)) + :draggable (dm/str can-edit) :overlay true :title (tr "labels.loading")}]))])) @@ -233,7 +233,7 @@ (mf/defc grid-item {:wrap [mf/memo]} - [{:keys [file origin library-view? you-viewer?] :as props}] + [{:keys [file origin library-view? can-edit] :as props}] (let [file-id (:id file) ;; FIXME: this breaks react hooks rule, hooks should never to @@ -276,10 +276,10 @@ on-drag-start (mf/use-fn - (mf/deps selected-files you-viewer?) + (mf/deps selected-files can-edit) (fn [event] (st/emit! (dd/hide-file-menu)) - (when-not you-viewer? + (when can-edit (let [offset (dom/get-offset-position (.-nativeEvent event)) select-current? (not (contains? selected-files (:id file))) @@ -359,7 +359,7 @@ {:class (stl/css-case :selected selected? :library library-view?) :ref node-ref :title (:name file) - :draggable (dm/str (not you-viewer?)) + :draggable (dm/str can-edit) :on-click on-select :on-key-down handle-key-down :on-double-click on-navigate @@ -372,7 +372,7 @@ [:& grid-item-library {:file file}] [:& grid-item-thumbnail {:file-id (:id file) - :you-viewer? you-viewer? + :can-edit can-edit :revn (:revn file) :thumbnail-id (:thumbnail-id file) :background-color (dm/get-in file [:data :options :background])}]) @@ -408,7 +408,7 @@ :show? (:menu-open dashboard-local) :left (+ 24 (:x (:menu-pos dashboard-local))) :top (:y (:menu-pos dashboard-local)) - :you-viewer? you-viewer? + :can-edit can-edit :navigate? true :on-edit on-edit :on-menu-close on-menu-close @@ -416,7 +416,7 @@ :parent-id (str file-id "-action-menu")}]])]]]]])) (mf/defc grid - [{:keys [files project origin limit library-view? create-fn you-viewer?] :as props}] + [{:keys [files project origin limit library-view? create-fn can-edit] :as props}] (let [dragging? (mf/use-state false) project-id (:id project) node-ref (mf/use-var nil) @@ -433,7 +433,7 @@ on-drag-enter (mf/use-fn (fn [e] - (when-not you-viewer? + (when can-edit (when (and (not (dnd/has-type? e "penpot/files")) (or (dnd/has-type? e "Files") (dnd/has-type? e "application/x-moz-file"))) @@ -464,7 +464,7 @@ (import-files (.-files (.-dataTransfer e))))))] [:div {:class (stl/css :dashboard-grid) - :dragabble (dm/str (not you-viewer?)) + :dragabble (dm/str can-edit) :on-drag-enter on-drag-enter :on-drag-over on-drag-over :on-drag-leave on-drag-leave @@ -486,18 +486,18 @@ :key (:id item) :navigate? true :origin origin - :you-viewer? you-viewer? + :can-edit can-edit :library-view? library-view?}])]) :else [:& empty-placeholder {:limit limit - :you-viewer? you-viewer? + :can-edit can-edit :create-fn create-fn :origin origin}])])) (mf/defc line-grid-row - [{:keys [files selected-files dragging? limit you-viewer?] :as props}] + [{:keys [files selected-files dragging? limit can-edit] :as props}] (let [elements limit limit (if dragging? (dec limit) limit)] [:ul {:class (stl/css :grid-row :no-wrap) @@ -511,12 +511,12 @@ {:id (:id item) :file item :selected-files selected-files - :you-viewer? you-viewer? + :can-edit can-edit :key (:id item) :navigate? false}])])) (mf/defc line-grid - [{:keys [project team files limit create-fn you-viewer?] :as props}] + [{:keys [project team files limit create-fn can-edit] :as props}] (let [dragging? (mf/use-state false) project-id (:id project) team-id (:id team) @@ -535,9 +535,9 @@ on-drag-enter (mf/use-fn - (mf/deps selected-project you-viewer?) + (mf/deps selected-project can-edit) (fn [e] - (when-not you-viewer? + (when can-edit (cond (dnd/has-type? e "penpot/files") (do @@ -595,7 +595,7 @@ (import-files (.-files (.-dataTransfer e)))))))] [:div {:class (stl/css :dashboard-grid) - :dragabble (dm/str (not you-viewer?)) + :dragabble (dm/str can-edit) :on-drag-enter on-drag-enter :on-drag-over on-drag-over :on-drag-leave on-drag-leave @@ -609,12 +609,12 @@ :team-id team-id :selected-files selected-files :dragging? @dragging? - :you-viewer? you-viewer? + :can-edit can-edit :limit limit}] :else [:& empty-placeholder {:dragging? @dragging? :limit limit - :you-viewer? you-viewer? + :can-edit can-edit :create-fn create-fn}])])) diff --git a/frontend/src/app/main/ui/dashboard/libraries.cljs b/frontend/src/app/main/ui/dashboard/libraries.cljs index 2ef394fa8..e883c5f0c 100644 --- a/frontend/src/app/main/ui/dashboard/libraries.cljs +++ b/frontend/src/app/main/ui/dashboard/libraries.cljs @@ -19,9 +19,11 @@ [rumext.v2 :as mf])) (mf/defc libraries-page - [{:keys [team you-viewer?] :as props}] + {::mf/props :obj} + [{:keys [team] :as props}] (let [files-map (mf/deref refs/dashboard-shared-files) projects (mf/deref refs/dashboard-projects) + can-edit (-> team :permissions :can-edit) default-project (->> projects vals (d/seek :is-default)) @@ -56,6 +58,6 @@ :project default-project :origin :libraries :limit limit - :you-viewer? you-viewer? + :can-edit can-edit :library-view? components-v2}]]])) diff --git a/frontend/src/app/main/ui/dashboard/placeholder.cljs b/frontend/src/app/main/ui/dashboard/placeholder.cljs index f49b795ae..08e1b150d 100644 --- a/frontend/src/app/main/ui/dashboard/placeholder.cljs +++ b/frontend/src/app/main/ui/dashboard/placeholder.cljs @@ -14,7 +14,7 @@ [rumext.v2 :as mf])) (mf/defc empty-placeholder - [{:keys [dragging? limit origin create-fn you-viewer?]}] + [{:keys [dragging? limit origin create-fn can-edit]}] (let [on-click (mf/use-fn (mf/deps create-fn) @@ -28,11 +28,14 @@ [:li {:class (stl/css :grid-item :grid-empty-placeholder :dragged)}]] (= :libraries origin) - [:> empty-placeholder* {:title (tr "dashboard.empty-placeholder-libraries-title") - :type 2 - :subtitle (when you-viewer? (tr "dashboard.empty-placeholder-libraries-subtitle-viewer-role")) - :class (stl/css :empty-placeholder-libraries)} - (when-not you-viewer? + [:> empty-placeholder* + {:title (tr "dashboard.empty-placeholder-libraries-title") + :type 2 + :subtitle (when-not can-edit + (tr "dashboard.empty-placeholder-libraries-subtitle-viewer-role")) + :class (stl/css :empty-placeholder-libraries)} + + (when can-edit [:> i18n/tr-html* {:content (tr "dashboard.empty-placeholder-libraries") :class (stl/css :placeholder-markdown) :tag-name "span"}])] diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index 34903f35f..3c85f5c41 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.dashboard.projects (:require-macros [app.main.style :as stl]) (:require - [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.main.data.dashboard :as dd] [app.main.data.events :as ev] @@ -46,12 +45,12 @@ (mf/defc header {::mf/wrap [mf/memo]} - [{:keys [you-viewer?]}] + [{:keys [can-edit]}] (let [on-click (mf/use-fn #(st/emit! (dd/create-project)))] [:header {:class (stl/css :dashboard-header) :data-testid "dashboard-header"} [:div#dashboard-projects-title {:class (stl/css :dashboard-title)} [:h1 (tr "dashboard.projects-title")]] - (when-not you-viewer? + (when can-edit [:button {:class (stl/css :btn-secondary :btn-small) :on-click on-click :data-testid "new-project-button"} @@ -101,13 +100,13 @@ (l/derived :builtin-templates st/state)) (mf/defc project-item - [{:keys [project first? team files you-viewer?] :as props}] + [{:keys [project first? team files can-edit] :as props}] (let [locale (mf/deref i18n/locale) file-count (or (:count project) 0) project-id (:id project) is-draft-proyect (:is-default project) team-id (:id team) - empty-state-viewer (and you-viewer? + empty-state-viewer (and (not can-edit) (= 0 file-count)) dstate (mf/deref refs/dashboard-local) @@ -225,7 +224,7 @@ :title (if (:is-default project) (tr "labels.drafts") (:name project)) - :on-context-menu (when-not you-viewer? on-menu-click)} + :on-context-menu (when can-edit on-menu-click)} (if (:is-default project) (tr "labels.drafts") (:name project))]) @@ -246,7 +245,7 @@ (when-not (:is-default project) [:> pin-button* {:class (stl/css :pin-button) :is-pinned (:is-pinned project) :on-click toggle-pin :tab-index 0}]) - (when-not you-viewer? + (when ^boolean can-edit [:button {:class (stl/css :add-file-btn) :on-click on-create-click :title (tr "dashboard.new-file") @@ -255,7 +254,7 @@ :on-key-down handle-create-click} add-icon]) - (when-not you-viewer? + (when ^boolean can-edit [:button {:class (stl/css :options-btn) :on-click on-menu-click :title (tr "dashboard.options") @@ -263,7 +262,8 @@ :data-testid "project-options" :on-key-down handle-menu-click} menu-icon])] - (when-not you-viewer? + + (when ^boolean can-edit [:& project-menu {:project project :show? (:menu-open @local) @@ -289,7 +289,7 @@ :team team :files files :create-fn create-file - :you-viewer? you-viewer? + :can-edit can-edit :limit limit}])] (when (and (> limit 0) @@ -309,14 +309,16 @@ (mf/defc projects-section [{:keys [team projects profile] :as props}] + (let [projects (->> (vals projects) (sort-by :modified-at) (reverse)) recent-map (mf/deref recent-files-ref) - you-owner? (dm/get-in team [:permissions :is-owner]) - you-admin? (dm/get-in team [:permissions :is-admin]) - you-viewer? (not (dm/get-in team [:permissions :can-edit])) - can-invite? (or you-owner? you-admin?) + permisions (:permissions team) + + can-edit (:can-edit permisions) + can-invite (or (:is-owner permisions) + (:is-admin permisions)) show-team-hero* (mf/use-state #(get storage/global ::show-team-hero true)) show-team-hero? (deref show-team-hero*) @@ -348,11 +350,11 @@ (when (seq projects) [:* - [:& header {:you-viewer? you-viewer?}] + [:& header {:can-edit can-edit}] [:div {:class (stl/css :projects-container)} [:* (when (and show-team-hero? - can-invite? + can-invite (not is-defalt-team?)) [:> team-hero* {:team team :on-close on-close}]) @@ -362,7 +364,7 @@ :with-team-hero (and (not is-my-penpot) (not is-defalt-team?) show-team-hero? - can-invite?))} + can-invite))} (for [{:keys [id] :as project} projects] (let [files (when recent-map (->> (vals recent-map) @@ -371,6 +373,6 @@ [:& project-item {:project project :team team :files files - :you-viewer? you-viewer? + :can-edit can-edit :first? (= project (first projects)) :key id}]))]]]]))) diff --git a/frontend/src/app/main/ui/dashboard/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs index 391fdccec..1f744d632 100644 --- a/frontend/src/app/main/ui/dashboard/team.cljs +++ b/frontend/src/app/main/ui/dashboard/team.cljs @@ -255,28 +255,30 @@ (mf/defc rol-info {::mf/wrap-props false} [{:keys [member team on-set-admin on-set-editor on-set-owner on-set-viewer profile]}] - (let [member-is-owner? (:is-owner member) - member-is-admin? (and (:is-admin member) (not member-is-owner?)) - member-is-editor? (and (:can-edit member) (and (not member-is-admin?) (not member-is-owner?))) - show? (mf/use-state false) + (let [member-is-owner (:is-owner member) + member-is-admin (and (:is-admin member) (not member-is-owner)) + member-is-editor (and (:can-edit member) (and (not member-is-admin) (not member-is-owner))) + show? (mf/use-state false) - you-owner? (dm/get-in team [:permissions :is-owner]) - you-admin? (dm/get-in team [:permissions :is-admin]) - is-you? (= (:id profile) (:id member)) + permissions (:permissions team) + is-owner (:is-owner permissions) + is-admin (:is-admin permissions) - can-change-rol? (or you-owner? you-admin?) - not-superior? (or you-owner? (and can-change-rol? (or member-is-admin? member-is-editor?))) + is-you (= (:id profile) (:id member)) - role (cond - member-is-owner? "labels.owner" - member-is-admin? "labels.admin" - member-is-editor? "labels.editor" - :else "labels.viewer") + can-change-rol (or is-owner is-admin) + not-superior (or is-admin (and can-change-rol (or member-is-admin member-is-editor))) - on-show (mf/use-fn #(reset! show? true)) - on-hide (mf/use-fn #(reset! show? false))] + role (cond + member-is-owner "labels.owner" + member-is-admin "labels.admin" + member-is-editor "labels.editor" + :else "labels.viewer") + + on-show (mf/use-fn #(reset! show? true)) + on-hide (mf/use-fn #(reset! show? false))] [:* - (if (and can-change-rol? not-superior? (not (and is-you? you-owner?))) + (if (and can-change-rol not-superior (not (and is-you is-owner))) [:div {:class (stl/css :rol-selector :has-priv) :on-click on-show} [:span {:class (stl/css :rol-label)} (tr role)] @@ -295,7 +297,7 @@ [:li {:on-click on-set-viewer :class (stl/css :rol-dropdown-item)} (tr "labels.viewer")] - (when you-owner? + (when is-owner [:li {:on-click (partial on-set-owner member) :class (stl/css :rol-dropdown-item)} (tr "labels.owner")])]]])) @@ -320,7 +322,6 @@ :on-click on-show} menu-icon] - [:& dropdown {:show @show? :on-close on-hide} [:ul {:class (stl/css :actions-dropdown)} (when is-you? @@ -910,12 +911,13 @@ (tr "dashboard.webhooks.create")]]) (mf/defc webhook-actions - {::mf/wrap-props false} - [{:keys [on-edit on-delete can-edit?]}] + {::mf/props :obj + ::mf/private true} + [{:keys [on-edit on-delete can-edit]}] (let [show? (mf/use-state false) on-show (mf/use-fn #(reset! show? true)) on-hide (mf/use-fn #(reset! show? false))] - (if can-edit? + (if can-edit [:* [:button {:class (stl/css :menu-btn) :on-click on-show} @@ -948,7 +950,7 @@ creator-id (:profile-id webhook) profile (mf/deref refs/profile) user-id (:id profile) - can-edit? (or (:can-edit permissions) + can-edit (or (:can-edit permissions) (= creator-id user-id)) on-edit (mf/use-fn @@ -1002,8 +1004,8 @@ [:div {:class (stl/css :table-field :actions)} [:& webhook-actions {:on-edit on-edit - :can-edit? can-edit? - :on-delete on-delete}]]])) + :on-delete on-delete + :can-edit can-edit}]]])) (mf/defc webhooks-list {::mf/wrap-props false} @@ -1053,9 +1055,9 @@ stats (mf/deref refs/dashboard-team-stats) - you-owner? (get-in team [:permissions :is-owner]) - you-admin? (get-in team [:permissions :is-admin]) - can-edit? (or you-owner? you-admin?) + permissions (:permissions team) + can-edit (or (:is-owner permissions) + (:is-admin permissions)) on-image-click (mf/use-callback #(dom/click (mf/ref-val finput))) @@ -1086,13 +1088,13 @@ [:div {:class (stl/css :block-text)} (:name team)] [:div {:class (stl/css :team-icon)} - (when can-edit? + (when can-edit [:button {:class (stl/css :update-overlay) :on-click on-image-click} image-icon]) [:img {:class (stl/css :team-image) :src (cfg/resolve-team-photo-url team)}] - (when can-edit? + (when can-edit [:& file-uploader {:accept "image/jpeg,image/png" :multi false :ref finput diff --git a/frontend/src/app/main/ui/onboarding/team_choice.cljs b/frontend/src/app/main/ui/onboarding/team_choice.cljs index 4c22e6dcd..0fe0f961b 100644 --- a/frontend/src/app/main/ui/onboarding/team_choice.cljs +++ b/frontend/src/app/main/ui/onboarding/team_choice.cljs @@ -68,9 +68,8 @@ (mf/defc team-form-step-2 {::mf/props :obj} [{:keys [name on-back go-to-team?]}] - (let [initial (mf/use-memo - #(do {:role "editor" - :name name})) + (let [initial (mf/with-memo [] + {:role "editor" :name name}) form (fm/use-form :schema schema:invite-form :initial initial) diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs index 96ac09b30..082c7cb52 100644 --- a/frontend/src/app/main/ui/workspace.cljs +++ b/frontend/src/app/main/ui/workspace.cljs @@ -165,16 +165,16 @@ (let [layout (mf/deref refs/workspace-layout) wglobal (mf/deref refs/workspace-global) - + team (mf/deref refs/team) file (mf/deref refs/workspace-file) project (mf/deref refs/workspace-project) team-id (:team-id project) file-name (:name file) + permissions (:permissions team) - user-viewer? (not (dm/get-in file [:permissions :can-edit])) - read-only? (or (mf/deref refs/workspace-read-only?) - user-viewer?) + read-only? (mf/deref refs/workspace-read-only?) + read-only? (or read-only? (not (:can-edit permissions))) file-ready* (mf/with-memo [file-id] (make-file-ready-ref file-id)) @@ -214,7 +214,7 @@ [:& (mf/provider ctx/current-page-id) {:value page-id} [:& (mf/provider ctx/components-v2) {:value components-v2?} [:& (mf/provider ctx/workspace-read-only?) {:value read-only?} - [:& (mf/provider ctx/user-viewer?) {:value user-viewer?} + [:& (mf/provider ctx/team-permissions) {:value permissions} [:section {:class (stl/css :workspace) :style {:background-color background-color :touch-action "none"}} diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index c5c5599f9..d3e0e3122 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -534,15 +534,17 @@ [:& menu-entry {:title (tr "workspace.assets.duplicate") :on-click do-duplicate}]])) -(mf/defc viewport-context-menu - [{:keys [read-only?]}] +(mf/defc viewport-context-menu* + {::mf/props :obj} + [] (let [focus (mf/deref refs/workspace-focus-selected) + read-only? (mf/use-ctx ctx/workspace-read-only?) do-paste #(st/emit! (dw/paste-from-clipboard)) do-hide-ui #(st/emit! (-> (dw/toggle-layout-flag :hide-ui) (vary-meta assoc ::ev/origin "workspace-context-menu"))) do-toggle-focus-mode #(st/emit! (dw/toggle-focus-mode))] [:* - (when-not read-only? + (when-not ^boolean read-only? [:& menu-entry {:title (tr "workspace.shape.menu.paste") :shortcut (sc/get-tooltip :paste) :on-click do-paste}]) @@ -640,26 +642,26 @@ :disabled (and (not single?) (not can-merge?))}]])) +;; FIXME: optimize because it is rendered always + (mf/defc context-menu [] - (let [mdata (mf/deref menu-ref) - top (- (get-in mdata [:position :y]) 20) - left (get-in mdata [:position :x]) - dropdown-ref (mf/use-ref) - read-only? (mf/use-ctx ctx/workspace-read-only?)] + (let [mdata (mf/deref menu-ref) + top (- (get-in mdata [:position :y]) 20) + left (get-in mdata [:position :x]) + dropdown-ref (mf/use-ref) + read-only? (mf/use-ctx ctx/workspace-read-only?)] - (mf/use-effect - (mf/deps mdata) - #(let [dropdown (mf/ref-val dropdown-ref)] - (when dropdown - (let [bounding-rect (dom/get-bounding-rect dropdown) - window-size (dom/get-window-size) - delta-x (max (- (+ (:right bounding-rect) 250) (:width window-size)) 0) - delta-y (max (- (:bottom bounding-rect) (:height window-size)) 0) - new-style (str "top: " (- top delta-y) "px; " - "left: " (- left delta-x) "px;")] - (when (or (> delta-x 0) (> delta-y 0)) - (.setAttribute ^js dropdown "style" new-style)))))) + (mf/with-effect [mdata] + (when-let [dropdown (mf/ref-val dropdown-ref)] + (let [bounding-rect (dom/get-bounding-rect dropdown) + window-size (dom/get-window-size) + delta-x (max (- (+ (:right bounding-rect) 250) (:width window-size)) 0) + delta-y (max (- (:bottom bounding-rect) (:height window-size)) 0) + new-style (str "top: " (- top delta-y) "px; " + "left: " (- left delta-x) "px;")] + (when (or (> delta-x 0) (> delta-y 0)) + (.setAttribute ^js dropdown "style" new-style))))) [:& dropdown {:show (boolean mdata) :on-close #(st/emit! dw/hide-context-menu)} @@ -669,11 +671,11 @@ :on-context-menu prevent-default} [:ul {:class (stl/css :context-list)} - (if read-only? - [:& viewport-context-menu {:mdata mdata :read-only? read-only?}] + (if ^boolean read-only? + [:> viewport-context-menu* {:mdata mdata}] (case (:kind mdata) :shape [:& shape-context-menu {:mdata mdata}] :page [:& page-item-context-menu {:mdata mdata}] :grid-track [:& grid-track-context-menu {:mdata mdata}] :grid-cells [:& grid-cells-context-menu {:mdata mdata}] - [:& viewport-context-menu {:mdata mdata}]))]]])) + [:& viewport-context-menu* {:mdata mdata}]))]]])) diff --git a/frontend/src/app/main/ui/workspace/main_menu.cljs b/frontend/src/app/main/ui/workspace/main_menu.cljs index 19545708d..2739ede14 100644 --- a/frontend/src/app/main/ui/workspace/main_menu.cljs +++ b/frontend/src/app/main/ui/workspace/main_menu.cljs @@ -42,8 +42,9 @@ ;; --- Header menu and submenus -(mf/defc help-info-menu - {::mf/wrap-props false +(mf/defc help-info-menu* + {::mf/props :obj + ::mf/private true ::mf/wrap [mf/memo]} [{:keys [layout on-close]}] (let [nav-to-helpc-center @@ -172,8 +173,9 @@ [:span {:class (stl/css-case :feedback true :item-name true)} (tr "labels.give-feedback")]])])) -(mf/defc preferences-menu - {::mf/wrap-props false +(mf/defc preferences-menu* + {::mf/props :obj + ::mf/private true ::mf/wrap [mf/memo]} [{:keys [layout profile toggle-flag on-close toggle-theme]}] (let [show-nudge-options (mf/use-fn #(modal/show! {:type :nudge-option}))] @@ -283,8 +285,9 @@ (for [sc (scd/split-sc (sc/get-tooltip :toggle-theme))] [:span {:class (stl/css :shortcut-key) :key sc} sc])]]])) -(mf/defc view-menu - {::mf/wrap-props false +(mf/defc view-menu* + {::mf/props :obj + ::mf/private true ::mf/wrap [mf/memo]} [{:keys [layout toggle-flag on-close]}] (let [read-only? (mf/use-ctx ctx/workspace-read-only?) @@ -412,13 +415,17 @@ (for [sc (scd/split-sc (sc/get-tooltip :hide-ui))] [:span {:class (stl/css :shortcut-key) :key sc} sc])]]])) -(mf/defc edit-menu - {::mf/wrap-props false +(mf/defc edit-menu* + {::mf/props :obj + ::mf/private true ::mf/wrap [mf/memo]} - [{:keys [on-close user-viewer?]}] + [{:keys [on-close]}] (let [select-all (mf/use-fn #(st/emit! (dw/select-all))) undo (mf/use-fn #(st/emit! dwu/undo)) - redo (mf/use-fn #(st/emit! dwu/redo))] + redo (mf/use-fn #(st/emit! dwu/redo)) + perms (mf/use-ctx ctx/team-permissions) + can-edit (:can-edit perms)] + [:& dropdown-menu {:show true :list-class (stl/css-case :sub-menu true :edit true) @@ -439,38 +446,39 @@ :key sc} sc])]] - (when-not :user-viewer? user-viewer? - [:> dropdown-menu-item* {:class (stl/css :submenu-item) - :on-click undo - :on-key-down (fn [event] - (when (kbd/enter? event) - (undo event))) - :id "file-menu-undo"} - [:span {:class (stl/css :item-name)} (tr "workspace.header.menu.undo")] - [:span {:class (stl/css :shortcut)} - (for [sc (scd/split-sc (sc/get-tooltip :undo))] - [:span {:class (stl/css :shortcut-key) - :key sc} - sc])]]) + (when can-edit + [:> dropdown-menu-item* {:class (stl/css :submenu-item) + :on-click undo + :on-key-down (fn [event] + (when (kbd/enter? event) + (undo event))) + :id "file-menu-undo"} + [:span {:class (stl/css :item-name)} (tr "workspace.header.menu.undo")] + [:span {:class (stl/css :shortcut)} + (for [sc (scd/split-sc (sc/get-tooltip :undo))] + [:span {:class (stl/css :shortcut-key) + :key sc} + sc])]]) - (when-not :user-viewer? user-viewer? - [:> dropdown-menu-item* {:class (stl/css :submenu-item) - :on-click redo - :on-key-down (fn [event] - (when (kbd/enter? event) - (redo event))) - :id "file-menu-redo"} - [:span {:class (stl/css :item-name)} (tr "workspace.header.menu.redo")] - [:span {:class (stl/css :shortcut)} + (when can-edit + [:> dropdown-menu-item* {:class (stl/css :submenu-item) + :on-click redo + :on-key-down (fn [event] + (when (kbd/enter? event) + (redo event))) + :id "file-menu-redo"} + [:span {:class (stl/css :item-name)} (tr "workspace.header.menu.redo")] + [:span {:class (stl/css :shortcut)} - (for [sc (scd/split-sc (sc/get-tooltip :redo))] - [:span {:class (stl/css :shortcut-key) - :key sc} - sc])]])])) + (for [sc (scd/split-sc (sc/get-tooltip :redo))] + [:span {:class (stl/css :shortcut-key) + :key sc} + sc])]])])) -(mf/defc file-menu - {::mf/wrap-props false} - [{:keys [on-close file user-viewer?]}] +(mf/defc file-menu* + {::mf/props :obj + ::mf/private true} + [{:keys [on-close file can-edit]}] (let [file-id (:id file) shared? (:is-shared file) @@ -564,7 +572,7 @@ :id "file-menu-remove-shared"} [:span {:class (stl/css :item-name)} (tr "dashboard.unpublish-shared")]] - (when-not user-viewer? + (when can-edit [:> dropdown-menu-item* {:class (stl/css :submenu-item) :on-click on-add-shared :on-key-down on-add-shared-key-down @@ -613,8 +621,9 @@ [:span {:class (stl/css :item-name)} (tr "dashboard.export-frames")]])])) -(mf/defc plugins-menu - {::mf/wrap-props false +(mf/defc plugins-menu* + {::mf/props :obj + ::mf/private true ::mf/wrap [mf/memo]} [{:keys [open-plugins on-close]}] (when (features/active-feature? @st/state "plugins/runtime") @@ -659,15 +668,13 @@ [:span {:class (stl/css :item-name)} name]])]))) (mf/defc menu - {::mf/wrap-props false} + {::mf/props :obj} [{:keys [layout file profile]}] (let [show-menu* (mf/use-state false) show-menu? (deref show-menu*) sub-menu* (mf/use-state false) sub-menu (deref sub-menu*) - user-viewer? (mf/use-ctx ctx/user-viewer?) - open-menu (mf/use-fn (fn [event] @@ -814,24 +821,21 @@ (case sub-menu :file - [:& file-menu - {:file file - :on-close close-sub-menu - :user-viewer? user-viewer?}] + [:> file-menu* {:file file + :on-close close-sub-menu}] :edit - [:& edit-menu - {:on-close close-sub-menu - :user-viewer? user-viewer?}] + [:> edit-menu* + {:on-close close-sub-menu}] :view - [:& view-menu + [:> view-menu* {:layout layout :toggle-flag toggle-flag :on-close close-sub-menu}] :preferences - [:& preferences-menu + [:> preferences-menu* {:layout layout :profile profile :toggle-flag toggle-flag @@ -839,12 +843,12 @@ :on-close close-sub-menu}] :plugins - [:& plugins-menu + [:& plugins-menu* {:open-plugins open-plugins-manager :on-close close-sub-menu}] :help-info - [:& help-info-menu + [:& help-info-menu* {:layout layout :on-close close-sub-menu}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index a7505dde3..a63558346 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -134,8 +134,7 @@ ::mf/props :obj} [{:keys [selected shapes shapes-with-children page-id file-id on-change-section on-expand]}] (let [objects (mf/deref refs/workspace-page-objects) - - user-viewer? (mf/use-ctx ctx/user-viewer?) + permissions (mf/use-ctx ctx/team-permissions) selected-shapes (into [] (keep (d/getf objects)) selected) first-selected-shape (first selected-shapes) @@ -176,10 +175,7 @@ tabs - (if user-viewer? - #js [#js {:label (tr "workspace.options.inspect") - :id "inspect" - :content inspect-content}] + (if (:can-edit permissions) #js [#js {:label (tr "workspace.options.design") :id "design" :content design-content} @@ -189,6 +185,9 @@ :content interactions-content} #js {:label (tr "workspace.options.inspect") + :id "inspect" + :content inspect-content}] + #js [#js {:label (tr "workspace.options.inspect") :id "inspect" :content inspect-content}])] diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs index fb2c6bc37..286cc5883 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs @@ -30,11 +30,11 @@ (mf/defc page-item {::mf/wrap-props false} [{:keys [page index deletable? selected? editing? hovering?]}] - (let [input-ref (mf/use-ref) - id (:id page) - delete-fn (mf/use-fn (mf/deps id) #(st/emit! (dw/delete-page id))) - navigate-fn (mf/use-fn (mf/deps id) #(st/emit! :interrupt (dw/go-to-page id))) - workspace-read-only? (mf/use-ctx ctx/workspace-read-only?) + (let [input-ref (mf/use-ref) + id (:id page) + delete-fn (mf/use-fn (mf/deps id) #(st/emit! (dw/delete-page id))) + navigate-fn (mf/use-fn (mf/deps id) #(st/emit! :interrupt (dw/go-to-page id))) + read-only? (mf/use-ctx ctx/workspace-read-only?) on-delete (mf/use-fn @@ -47,11 +47,11 @@ on-double-click (mf/use-fn - (mf/deps workspace-read-only?) + (mf/deps read-only?) (fn [event] (dom/prevent-default event) (dom/stop-propagation event) - (when-not workspace-read-only? + (when-not read-only? (st/emit! (dw/start-rename-page-item id))))) on-blur @@ -86,15 +86,15 @@ :data {:id id :index index :name (:name page)} - :draggable? (not workspace-read-only?)) + :draggable? (not read-only?)) on-context-menu (mf/use-fn - (mf/deps id workspace-read-only?) + (mf/deps id read-only?) (fn [event] (dom/prevent-default event) (dom/stop-propagation event) - (when-not workspace-read-only? + (when-not read-only? (let [position (dom/get-client-position event)] (st/emit! (dw/show-page-item-context-menu {:position position @@ -147,7 +147,7 @@ [:span {:class (stl/css :page-name) :data-testid "page-name"} (:name page)] [:div {:class (stl/css :page-actions)} - (when (and deletable? (not workspace-read-only?)) + (when (and deletable? (not read-only?)) [:button {:on-click on-delete} i/delete])]])]])) @@ -206,8 +206,7 @@ (st/emit! (dw/create-page {:file-id file-id :project-id project-id})) (-> event dom/get-current-target dom/blur!))) read-only? (mf/use-ctx ctx/workspace-read-only?) - user-viewer? (mf/use-ctx ctx/user-viewer?)] - + permissions (mf/use-ctx ctx/team-permissions)] [:div {:class (stl/css :sitemap) :style #js {"--height" (str size "px")}} @@ -220,7 +219,7 @@ :class (stl/css :title-spacing-sitemap)} (if ^boolean read-only? - (when (not ^boolean user-viewer?) + (when ^boolean (:can-edit permissions) [:& badge-notification {:is-focus true :size :small :content (tr "labels.view-only")}]) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 98d4d2f9b..0e906c47e 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -95,8 +95,11 @@ vbox' (mf/use-debounce 100 vbox) + permissions (mf/use-ctx ctx/team-permissions) + read-only? (mf/use-ctx ctx/workspace-read-only?) + ;; DEREFS - user-viewer? (mf/use-ctx ctx/user-viewer?) + drawing (mf/deref refs/workspace-drawing) focus (mf/deref refs/workspace-focus-selected) @@ -169,12 +172,11 @@ text-editing? (and edition (= :text (get-in base-objects [edition :type]))) grid-editing? (and edition (ctl/grid-layout? base-objects edition)) - workspace-read-only? (mf/use-ctx ctx/workspace-read-only?) mode-inspect? (= options-mode :inspect) on-click (actions/on-click hover selected edition drawing-path? drawing-tool space? selrect z?) - on-context-menu (actions/on-context-menu hover hover-ids workspace-read-only?) - on-double-click (actions/on-double-click hover hover-ids hover-top-frame-id drawing-path? base-objects edition drawing-tool z? workspace-read-only?) + on-context-menu (actions/on-context-menu hover hover-ids read-only?) + on-double-click (actions/on-double-click hover hover-ids hover-top-frame-id drawing-path? base-objects edition drawing-tool z? read-only?) comp-inst-ref (mf/use-ref false) on-drag-enter (actions/on-drag-enter comp-inst-ref) @@ -182,19 +184,19 @@ on-drag-end (actions/on-drag-over comp-inst-ref) on-drop (actions/on-drop file comp-inst-ref) on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? node-editing? grid-editing? - drawing-path? create-comment? space? panning z? workspace-read-only?) + drawing-path? create-comment? space? panning z? read-only?) on-pointer-up (actions/on-pointer-up disable-paste) on-pointer-enter (actions/on-pointer-enter in-viewport?) on-pointer-leave (actions/on-pointer-leave in-viewport?) on-pointer-move (actions/on-pointer-move move-stream) - on-move-selected (actions/on-move-selected hover hover-ids selected space? z? workspace-read-only?) - on-menu-selected (actions/on-menu-selected hover hover-ids selected workspace-read-only?) + on-move-selected (actions/on-move-selected hover hover-ids selected space? z? read-only?) + on-menu-selected (actions/on-menu-selected hover hover-ids selected read-only?) on-frame-enter (actions/on-frame-enter frame-hover) on-frame-leave (actions/on-frame-leave frame-hover) - on-frame-select (actions/on-frame-select selected workspace-read-only?) + on-frame-select (actions/on-frame-select selected read-only?) disable-events? (contains? layout :comments) show-comments? (= drawing-tool :comments) @@ -267,9 +269,9 @@ rule-area-size (/ rulers/ruler-area-size zoom)] - (hooks/setup-dom-events zoom disable-paste in-viewport? workspace-read-only? drawing-tool drawing-path?) + (hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool drawing-path?) (hooks/setup-viewport-size vport viewport-ref) - (hooks/setup-cursor cursor alt? mod? space? panning drawing-tool drawing-path? node-editing? z? workspace-read-only?) + (hooks/setup-cursor cursor alt? mod? space? panning drawing-tool drawing-path? node-editing? z? read-only?) (hooks/setup-keyboard alt? mod? space? z? shift?) (hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover measure-hover hover-ids hover-top-frame-id @hover-disabled? focus zoom show-measures?) @@ -278,7 +280,7 @@ (hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox) [:div {:class (stl/css :viewport) :style #js {"--zoom" zoom} :data-testid "viewport"} - (when-not user-viewer? + (when (:can-edit permissions) [:& top-bar/top-bar {:layout layout}]) [:div {:class (stl/css :viewport-overlays)} ;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap @@ -288,7 +290,7 @@ [:div {:style {:pointer-events (when-not (dbg/enabled? :html-text) "none") ;; some opacity because to debug auto-width events will fill the screen :opacity 0.6}} - (when-not workspace-read-only? + (when (and (:can-edit permissions) (not read-only?)) [:& stvh/viewport-texts {:key (dm/str "texts-" page-id) :page-id page-id diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index 6f104dedf..e3d65258f 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -41,11 +41,11 @@ (defn on-pointer-down [{:keys [id blocked hidden type]} selected edition drawing-tool text-editing? - node-editing? grid-editing? drawing-path? create-comment? space? panning z? workspace-read-only?] + node-editing? grid-editing? drawing-path? create-comment? space? panning z? read-only?] (mf/use-callback (mf/deps id blocked hidden type selected edition drawing-tool text-editing? node-editing? grid-editing? drawing-path? create-comment? @z? @space? - panning workspace-read-only?) + panning read-only?) (fn [bevent] ;; We need to handle editor related stuff here because ;; handling on editor dom node does not works properly. @@ -101,24 +101,24 @@ (cond node-editing? ;; Handle path node area selection - (when-not workspace-read-only? + (when-not read-only? (st/emit! (dwdp/handle-area-selection shift?))) drawing-tool - (when-not workspace-read-only? + (when-not read-only? (st/emit! (dd/start-drawing drawing-tool))) (or (not id) mod?) (st/emit! (dw/handle-area-selection shift?)) (not drawing-tool) - (when-not workspace-read-only? + (when-not read-only? (st/emit! (dw/start-move-selected id shift?))))))))))))) (defn on-move-selected - [hover hover-ids selected space? z? workspace-read-only?] + [hover hover-ids selected space? z? read-only?] (mf/use-callback - (mf/deps @hover @hover-ids selected @space? @z? workspace-read-only?) + (mf/deps @hover @hover-ids selected @space? @z? read-only?) (fn [bevent] (let [event (.-nativeEvent bevent) shift? (kbd/shift? event) @@ -132,20 +132,20 @@ (dom/prevent-default bevent) (dom/stop-propagation bevent) - (when-not (or workspace-read-only? @z?) + (when-not (or read-only? @z?) (st/emit! (dw/start-move-selected)))))))) (defn on-frame-select - [selected workspace-read-only?] + [selected read-only?] (mf/use-callback - (mf/deps selected workspace-read-only?) + (mf/deps selected read-only?) (fn [event id] (let [shift? (kbd/shift? event) selected? (contains? selected id) selected-drawtool (deref refs/selected-drawing-tool)] (st/emit! (when (or shift? (not selected?)) (dw/select-shape id shift?)) - (when (and (nil? selected-drawtool) (not shift?) (not workspace-read-only?)) + (when (and (nil? selected-drawtool) (not shift?) (not read-only?)) (dw/start-move-selected))))))) (defn on-frame-enter @@ -195,10 +195,10 @@ (st/emit! (dw/increase-zoom pt))))))))) (defn on-double-click - [hover hover-ids hover-top-frame-id drawing-path? objects edition drawing-tool z? workspace-read-only?] + [hover hover-ids hover-top-frame-id drawing-path? objects edition drawing-tool z? read-only?] (mf/use-callback - (mf/deps @hover @hover-ids @hover-top-frame-id drawing-path? edition drawing-tool @z? workspace-read-only?) + (mf/deps @hover @hover-ids @hover-top-frame-id drawing-path? edition drawing-tool @z? read-only?) (fn [event] (dom/stop-propagation event) (when-not @z? @@ -223,7 +223,7 @@ (fn [] (when (and (not drawing-path?) shape) (cond - (and editable? (not= id edition) (not workspace-read-only?)) + (and editable? (not= id edition) (not read-only?)) (st/emit! (dw/select-shape id) (dw/start-editing-selected)) @@ -231,16 +231,16 @@ (do (reset! hover selected-shape) (st/emit! (dw/select-shape (:id selected-shape)))) - (and (not selected-shape) (some? grid-layout-id) (not workspace-read-only?)) + (and (not selected-shape) (some? grid-layout-id) (not read-only?)) (st/emit! (dw/start-edition-mode grid-layout-id))))))))))) (defn on-context-menu - [hover hover-ids workspace-read-only?] + [hover hover-ids read-only?] (mf/use-fn - (mf/deps @hover @hover-ids workspace-read-only?) + (mf/deps @hover @hover-ids read-only?) (fn [event] (dom/prevent-default event) - ;;(when-not workspace-read-only? + ;;(when-not read-only? (when (or (dom/class? (dom/get-target event) "viewport-controls") (dom/child? (dom/get-target event) (dom/query ".grid-layout-editor")) (dom/class? (dom/get-target event) "viewport-selrect")) @@ -248,20 +248,20 @@ ;; Delayed callback because we need to wait to the previous context menu to be closed (ts/schedule #(st/emit! - (if (and (not workspace-read-only?) (some? @hover)) + (if (and (not read-only?) (some? @hover)) (dw/show-shape-context-menu {:position position :shape @hover :hover-ids @hover-ids}) (dw/show-context-menu {:position position}))))))))) (defn on-menu-selected - [hover hover-ids selected workspace-read-only?] + [hover hover-ids selected read-only?] (mf/use-callback - (mf/deps @hover @hover-ids selected workspace-read-only?) + (mf/deps @hover @hover-ids selected read-only?) (fn [event] (dom/prevent-default event) (dom/stop-propagation event) - (when-not workspace-read-only? + (when-not read-only? (let [position (dom/get-client-position event)] (st/emit! (dw/show-shape-context-menu {:position position :hover-ids @hover-ids}))))))) @@ -538,14 +538,14 @@ (st/emit! (dwm/upload-media-workspace params)))))))) (defn on-paste - [disable-paste in-viewport? workspace-read-only?] + [disable-paste in-viewport? read-only?] (mf/use-fn - (mf/deps workspace-read-only?) + (mf/deps read-only?) (fn [event] ;; We disable the paste just after mouse-up of a middle button so ;; when panning won't paste the content into the workspace (let [tag-name (-> event dom/get-target dom/get-tag-name)] (when (and (not (#{"INPUT" "TEXTAREA"} tag-name)) (not @disable-paste) - (not workspace-read-only?)) + (not read-only?)) (st/emit! (dw/paste-from-event event @in-viewport?))))))) diff --git a/frontend/test/frontend_tests/helpers/pages.cljs b/frontend/test/frontend_tests/helpers/pages.cljs index 74ad1c9f9..69e617004 100644 --- a/frontend/test/frontend_tests/helpers/pages.cljs +++ b/frontend/test/frontend_tests/helpers/pages.cljs @@ -39,7 +39,7 @@ :pages [] :pages-index {}} :workspace-libraries {} - :features/team #{"components/v2"}}) + :features-team #{"components/v2"}}) (def ^:private idmap (atom {})) diff --git a/frontend/test/frontend_tests/helpers/state.cljs b/frontend/test/frontend_tests/helpers/state.cljs index 2f73c4d8d..068a6cce9 100644 --- a/frontend/test/frontend_tests/helpers/state.cljs +++ b/frontend/test/frontend_tests/helpers/state.cljs @@ -20,7 +20,7 @@ :current-page-id nil :workspace-data nil :workspace-libraries {} - :features/team #{"components/v2"}}) + :features-team #{"components/v2"}}) (defn- on-error [cause] @@ -33,6 +33,7 @@ (let [state (-> initial-state (assoc :current-file-id (:id file) :current-page-id (cthf/current-page-id file) + :permissions {:can-edit true} :workspace-file (dissoc file :data) :workspace-data (:data file))) store (ptk/store {:state state :on-error on-error})]