mirror of
https://github.com/penpot/penpot.git
synced 2026-09-12 06:58:57 +00:00
✨ Allow login dialog on settings
This commit is contained in:
parent
7f53860296
commit
1f05511add
@ -26,6 +26,7 @@
|
|||||||
- Improved text layer resizing: Allow double-click on text bounding box to set auto-width/auto-height [Taiga #11577](https://tree.taiga.io/project/penpot/issue/11577)
|
- Improved text layer resizing: Allow double-click on text bounding box to set auto-width/auto-height [Taiga #11577](https://tree.taiga.io/project/penpot/issue/11577)
|
||||||
- Improve text layer auto-resize: auto-width switches to auto-height on horizontal resize, and only switches to fixed on vertical resize [Taiga #11578](https://tree.taiga.io/project/penpot/issue/11578)
|
- Improve text layer auto-resize: auto-width switches to auto-height on horizontal resize, and only switches to fixed on vertical resize [Taiga #11578](https://tree.taiga.io/project/penpot/issue/11578)
|
||||||
- Highlight first font in font selector search. Apply only on Enter or click. [Taiga #11579](https://tree.taiga.io/project/penpot/issue/11579)
|
- Highlight first font in font selector search. Apply only on Enter or click. [Taiga #11579](https://tree.taiga.io/project/penpot/issue/11579)
|
||||||
|
- Add the ability to show login dialog on profile settings [Github #6871](https://github.com/penpot/penpot/pull/6871)
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
|
|||||||
@ -102,23 +102,27 @@
|
|||||||
(print-trace! error)
|
(print-trace! error)
|
||||||
(print-data! error))))
|
(print-data! error))))
|
||||||
|
|
||||||
;; We receive a explicit authentication error;
|
;; We receive a explicit authentication error; If the uri is for
|
||||||
;; If the uri is for workspace, dashboard or view assign the
|
;; workspace, dashboard, viewer or settings, then assign the exception
|
||||||
;; exception for the 'Oops' page. Otherwise this explicitly clears
|
;; for show the error page. Otherwise this explicitly clears all
|
||||||
;; all profile data and redirect the user to the login page. This is
|
;; profile data and redirect the user to the login page. This is here
|
||||||
;; here and not in app.main.errors because of circular dependency.
|
;; and not in app.main.errors because of circular dependency.
|
||||||
(defmethod ptk/handle-error :authentication
|
(defmethod ptk/handle-error :authentication
|
||||||
[e]
|
[error]
|
||||||
(let [msg (tr "errors.auth.unable-to-login")
|
(let [message (tr "errors.auth.unable-to-login")
|
||||||
uri (.-href glob/location)
|
uri (rt/get-current-href)
|
||||||
show-oops? (or (str/includes? uri "workspace")
|
|
||||||
(str/includes? uri "dashboard")
|
show-error?
|
||||||
(str/includes? uri "view"))]
|
(or (str/includes? uri "workspace")
|
||||||
(if show-oops?
|
(str/includes? uri "dashboard")
|
||||||
(st/async-emit! (rt/assign-exception e))
|
(str/includes? uri "view")
|
||||||
|
(str/includes? uri "settings"))]
|
||||||
|
|
||||||
|
(if show-error?
|
||||||
|
(st/async-emit! (rt/assign-exception error))
|
||||||
(do
|
(do
|
||||||
(st/emit! (da/logout))
|
(st/emit! (da/logout))
|
||||||
(ts/schedule 500 #(st/emit! (ntf/warn msg)))))))
|
(ts/schedule 500 #(st/emit! (ntf/warn message)))))))
|
||||||
|
|
||||||
;; Error that happens on an active business model validation does not
|
;; Error that happens on an active business model validation does not
|
||||||
;; passes an validation (example: profile can't leave a team). From
|
;; passes an validation (example: profile can't leave a team). From
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.main.data.team :as dtm]
|
[app.main.data.team :as dtm]
|
||||||
|
[app.main.errors :as errors]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.router :as rt]
|
[app.main.router :as rt]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
@ -130,7 +131,10 @@
|
|||||||
(assoc query-params :team-id (:default-team-id profile))))))
|
(assoc query-params :team-id (:default-team-id profile))))))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit! (rt/assign-exception {:type :not-found})))))))))
|
(st/emit! (rt/assign-exception {:type :not-found}))))
|
||||||
|
|
||||||
|
(fn [cause]
|
||||||
|
(errors/on-error cause)))))))
|
||||||
|
|
||||||
(defn init-routes
|
(defn init-routes
|
||||||
[]
|
[]
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
(mf/with-effect [profile]
|
(mf/with-effect [profile]
|
||||||
(when (nil? profile)
|
(when (nil? profile)
|
||||||
(st/emit! (rt/nav :auth-login))))
|
(st/emit! (rt/assign-exception {:type :authentication}))))
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:> modal-container*]
|
[:> modal-container*]
|
||||||
|
|||||||
@ -69,9 +69,8 @@
|
|||||||
[:div {:class (stl/css :main-message)} (tr "errors.invite-invalid")]
|
[:div {:class (stl/css :main-message)} (tr "errors.invite-invalid")]
|
||||||
[:div {:class (stl/css :desc-message)} (tr "errors.invite-invalid.info")]])
|
[:div {:class (stl/css :desc-message)} (tr "errors.invite-invalid.info")]])
|
||||||
|
|
||||||
(mf/defc login-dialog
|
(mf/defc login-dialog*
|
||||||
{::mf/props :obj}
|
[]
|
||||||
[{:keys [show-dialog]}]
|
|
||||||
(let [current-section (mf/use-state :login)
|
(let [current-section (mf/use-state :login)
|
||||||
user-email (mf/use-state "")
|
user-email (mf/use-state "")
|
||||||
register-token (mf/use-state "")
|
register-token (mf/use-state "")
|
||||||
@ -94,9 +93,7 @@
|
|||||||
|
|
||||||
success-login
|
success-login
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn []
|
#(st/emit! (rt/reload true)))
|
||||||
(reset! show-dialog false)
|
|
||||||
(st/emit! (rt/reload true))))
|
|
||||||
|
|
||||||
success-register
|
success-register
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@ -117,7 +114,7 @@
|
|||||||
(reset! current-section :recovery-email-sent)))
|
(reset! current-section :recovery-email-sent)))
|
||||||
|
|
||||||
on-nav-root
|
on-nav-root
|
||||||
(mf/use-fn #(st/emit! (rt/nav-root)))]
|
(mf/use-fn #(st/emit! (rt/nav :auth-login {})))]
|
||||||
|
|
||||||
[:div {:class (stl/css :overlay)}
|
[:div {:class (stl/css :overlay)}
|
||||||
[:div {:class (stl/css :dialog-login)}
|
[:div {:class (stl/css :dialog-login)}
|
||||||
@ -203,11 +200,9 @@
|
|||||||
[:button {:on-click on-click} button-text]]]]))
|
[:button {:on-click on-click} button-text]]]]))
|
||||||
|
|
||||||
(mf/defc request-access*
|
(mf/defc request-access*
|
||||||
[{:keys [file-id team-id is-default is-workspace]}]
|
[{:keys [file-id team-id is-default is-workspace profile]}]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [requested* (mf/use-state {:sent false :already-requested false})
|
||||||
requested* (mf/use-state {:sent false :already-requested false})
|
|
||||||
requested (deref requested*)
|
requested (deref requested*)
|
||||||
show-dialog (mf/use-state true)
|
|
||||||
|
|
||||||
on-close
|
on-close
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@ -237,90 +232,47 @@
|
|||||||
(st/emit! (dcm/create-team-access-request
|
(st/emit! (dcm/create-team-access-request
|
||||||
(with-meta params mdata))))))]
|
(with-meta params mdata))))))]
|
||||||
|
|
||||||
[:*
|
(cond
|
||||||
(if (some? file-id)
|
is-default
|
||||||
(if is-workspace
|
[:& request-dialog {:title (tr "not-found.no-permission.project")
|
||||||
[:div {:class (stl/css :workspace)}
|
:button-text (tr "not-found.no-permission.go-dashboard")
|
||||||
[:div {:class (stl/css :workspace-left)}
|
:on-close on-close}]
|
||||||
i/logo-icon
|
|
||||||
[:div
|
|
||||||
[:div {:class (stl/css :project-name)} (tr "not-found.no-permission.project-name")]
|
|
||||||
[:div {:class (stl/css :file-name)} (tr "not-found.no-permission.penpot-file")]]]
|
|
||||||
[:div {:class (stl/css :workspace-right)}]]
|
|
||||||
|
|
||||||
[:div {:class (stl/css :viewer)}
|
(and (some? file-id) (:already-requested requested))
|
||||||
;; FIXME: the viewer header was never designed to be reused
|
[:& request-dialog {:title (tr "not-found.no-permission.already-requested.file")
|
||||||
;; from other parts of the application, and this code looks
|
:content [(tr "not-found.no-permission.already-requested.or-others.file")]
|
||||||
;; like a fast workaround reusing it as-is without a proper
|
:button-text (tr "not-found.no-permission.go-dashboard")
|
||||||
;; component adaptation for be able to use it easily it on
|
:on-close on-close}]
|
||||||
;; viewer context or static error page context
|
|
||||||
[:& viewer.header/header {:project
|
|
||||||
{:name (tr "not-found.no-permission.project-name")}
|
|
||||||
:index 0
|
|
||||||
:file {:name (tr "not-found.no-permission.penpot-file")}
|
|
||||||
:page nil
|
|
||||||
:frame nil
|
|
||||||
:permissions {:is-logged true}
|
|
||||||
:zoom 1
|
|
||||||
:section :interactions
|
|
||||||
:shown-thumbnails false
|
|
||||||
:interactions-mode nil}]])
|
|
||||||
|
|
||||||
[:div {:class (stl/css :dashboard)}
|
(:already-requested requested)
|
||||||
[:div {:class (stl/css :dashboard-sidebar)}
|
[:& request-dialog {:title (tr "not-found.no-permission.already-requested.project")
|
||||||
[:> sidebar*
|
:content [(tr "not-found.no-permission.already-requested.or-others.project")]
|
||||||
{:team nil
|
:button-text (tr "not-found.no-permission.go-dashboard")
|
||||||
:projects []
|
:on-close on-close}]
|
||||||
:project (:default-project-id profile)
|
|
||||||
:profile profile
|
|
||||||
:section :dashboard-projects
|
|
||||||
:search-term ""}]]])
|
|
||||||
|
|
||||||
(when @show-dialog
|
(:sent requested)
|
||||||
(cond
|
[:& request-dialog {:title (tr "not-found.no-permission.done.success")
|
||||||
(nil? profile)
|
:content [(tr "not-found.no-permission.done.remember")]
|
||||||
[:& login-dialog {:show-dialog show-dialog}]
|
:button-text (tr "not-found.no-permission.go-dashboard")
|
||||||
|
:on-close on-close}]
|
||||||
|
|
||||||
is-default
|
(some? file-id)
|
||||||
[:& request-dialog {:title (tr "not-found.no-permission.project")
|
[:& request-dialog {:title (tr "not-found.no-permission.file")
|
||||||
:button-text (tr "not-found.no-permission.go-dashboard")
|
:content [(tr "not-found.no-permission.you-can-ask.file")
|
||||||
:on-close on-close}]
|
(tr "not-found.no-permission.if-approves")]
|
||||||
|
:button-text (tr "not-found.no-permission.ask")
|
||||||
|
:on-button-click on-request-access
|
||||||
|
:cancel-text (tr "not-found.no-permission.go-dashboard")
|
||||||
|
:on-close on-close}]
|
||||||
|
|
||||||
(and (some? file-id) (:already-requested requested))
|
(some? team-id)
|
||||||
[:& request-dialog {:title (tr "not-found.no-permission.already-requested.file")
|
[:& request-dialog {:title (tr "not-found.no-permission.project")
|
||||||
:content [(tr "not-found.no-permission.already-requested.or-others.file")]
|
:content [(tr "not-found.no-permission.you-can-ask.project")
|
||||||
:button-text (tr "not-found.no-permission.go-dashboard")
|
(tr "not-found.no-permission.if-approves")]
|
||||||
:on-close on-close}]
|
:button-text (tr "not-found.no-permission.ask")
|
||||||
|
:on-button-click on-request-access
|
||||||
(:already-requested requested)
|
:cancel-text (tr "not-found.no-permission.go-dashboard")
|
||||||
[:& request-dialog {:title (tr "not-found.no-permission.already-requested.project")
|
:on-close on-close}])))
|
||||||
:content [(tr "not-found.no-permission.already-requested.or-others.project")]
|
|
||||||
:button-text (tr "not-found.no-permission.go-dashboard")
|
|
||||||
:on-close on-close}]
|
|
||||||
|
|
||||||
(:sent requested)
|
|
||||||
[:& request-dialog {:title (tr "not-found.no-permission.done.success")
|
|
||||||
:content [(tr "not-found.no-permission.done.remember")]
|
|
||||||
:button-text (tr "not-found.no-permission.go-dashboard")
|
|
||||||
:on-close on-close}]
|
|
||||||
|
|
||||||
(some? file-id)
|
|
||||||
[:& request-dialog {:title (tr "not-found.no-permission.file")
|
|
||||||
:content [(tr "not-found.no-permission.you-can-ask.file")
|
|
||||||
(tr "not-found.no-permission.if-approves")]
|
|
||||||
:button-text (tr "not-found.no-permission.ask")
|
|
||||||
:on-button-click on-request-access
|
|
||||||
:cancel-text (tr "not-found.no-permission.go-dashboard")
|
|
||||||
:on-close on-close}]
|
|
||||||
|
|
||||||
(some? team-id)
|
|
||||||
[:& request-dialog {:title (tr "not-found.no-permission.project")
|
|
||||||
:content [(tr "not-found.no-permission.you-can-ask.project")
|
|
||||||
(tr "not-found.no-permission.if-approves")]
|
|
||||||
:button-text (tr "not-found.no-permission.ask")
|
|
||||||
:on-button-click on-request-access
|
|
||||||
:cancel-text (tr "not-found.no-permission.go-dashboard")
|
|
||||||
:on-close on-close}]))]))
|
|
||||||
|
|
||||||
(mf/defc not-found*
|
(mf/defc not-found*
|
||||||
[]
|
[]
|
||||||
@ -484,29 +436,77 @@
|
|||||||
|
|
||||||
[:> internal-error* props])))
|
[:> internal-error* props])))
|
||||||
|
|
||||||
|
(mf/defc context-wrapper*
|
||||||
|
[{:keys [is-workspace is-dashboard is-viewer profile children]}]
|
||||||
|
[:*
|
||||||
|
(cond
|
||||||
|
is-workspace
|
||||||
|
[:div {:class (stl/css :workspace)}
|
||||||
|
[:div {:class (stl/css :workspace-left)}
|
||||||
|
i/logo-icon
|
||||||
|
[:div
|
||||||
|
[:div {:class (stl/css :project-name)} (tr "not-found.no-permission.project-name")]
|
||||||
|
[:div {:class (stl/css :file-name)} (tr "not-found.no-permission.penpot-file")]]]
|
||||||
|
[:div {:class (stl/css :workspace-right)}]]
|
||||||
|
|
||||||
|
is-viewer
|
||||||
|
[:div {:class (stl/css :viewer)}
|
||||||
|
;; FIXME: the viewer header was never designed to be reused
|
||||||
|
;; from other parts of the application, and this code looks
|
||||||
|
;; like a fast workaround reusing it as-is without a proper
|
||||||
|
;; component adaptation for be able to use it easily it on
|
||||||
|
;; viewer context or static error page context
|
||||||
|
[:& viewer.header/header {:project
|
||||||
|
{:name (tr "not-found.no-permission.project-name")}
|
||||||
|
:index 0
|
||||||
|
:file {:name (tr "not-found.no-permission.penpot-file")}
|
||||||
|
:page nil
|
||||||
|
:frame nil
|
||||||
|
:permissions {:is-logged true}
|
||||||
|
:zoom 1
|
||||||
|
:section :interactions
|
||||||
|
:shown-thumbnails false
|
||||||
|
:interactions-mode nil}]]
|
||||||
|
|
||||||
|
is-dashboard
|
||||||
|
[:div {:class (stl/css :dashboard)}
|
||||||
|
[:div {:class (stl/css :dashboard-sidebar)}
|
||||||
|
[:> sidebar*
|
||||||
|
{:team nil
|
||||||
|
:projects []
|
||||||
|
:project (:default-project-id profile)
|
||||||
|
:profile profile
|
||||||
|
:section :dashboard-projects
|
||||||
|
:search-term ""}]]])
|
||||||
|
|
||||||
|
children])
|
||||||
|
|
||||||
(mf/defc exception-page*
|
(mf/defc exception-page*
|
||||||
{::mf/props :obj}
|
{::mf/props :obj}
|
||||||
[{:keys [data route] :as props}]
|
[{:keys [data route] :as props}]
|
||||||
|
|
||||||
(let [type (:type data)
|
(let [type (:type data)
|
||||||
path (:path route)
|
path (:path route)
|
||||||
|
|
||||||
params (:query-params route)
|
params (:query-params route)
|
||||||
|
|
||||||
workspace? (str/includes? path "workspace")
|
workspace? (str/includes? path "workspace")
|
||||||
dashboard? (str/includes? path "dashboard")
|
dashboard? (str/includes? path "dashboard")
|
||||||
view? (str/includes? path "view")
|
view? (str/includes? path "view")
|
||||||
|
|
||||||
;; We store the request access info int this state
|
;; We store the request access info int this state
|
||||||
info* (mf/use-state nil)
|
info* (mf/use-state nil)
|
||||||
info (deref info*)
|
info (deref info*)
|
||||||
|
|
||||||
loaded? (get info :loaded false)
|
loaded? (get info :loaded false)
|
||||||
|
profile (mf/deref refs/profile)
|
||||||
|
|
||||||
|
auth-error?
|
||||||
|
(= type :authentication)
|
||||||
|
|
||||||
request-access?
|
request-access?
|
||||||
(and
|
(and
|
||||||
(or (= type :not-found)
|
(or (= type :not-found) auth-error?)
|
||||||
(= type :authentication))
|
|
||||||
(or workspace? dashboard? view?)
|
(or workspace? dashboard? view?)
|
||||||
(or (:file-id info)
|
(or (:file-id info)
|
||||||
(:team-id info)))]
|
(:team-id info)))]
|
||||||
@ -517,11 +517,25 @@
|
|||||||
(rx/subs! (partial reset! info*)
|
(rx/subs! (partial reset! info*)
|
||||||
(partial reset! info* {:loaded true})))))
|
(partial reset! info* {:loaded true})))))
|
||||||
|
|
||||||
(when loaded?
|
|
||||||
(if request-access?
|
(if auth-error?
|
||||||
[:> request-access* {:file-id (:file-id info)
|
[:> context-wrapper*
|
||||||
:team-id (:team-id info)
|
{:is-workspace workspace?
|
||||||
:is-default (:team-default info)
|
:is-dashboard dashboard?
|
||||||
:is-workspace workspace?}]
|
:is-viewer view?
|
||||||
[:> exception-section* props]))))
|
:profile profile}
|
||||||
|
[:> login-dialog* {}]]
|
||||||
|
|
||||||
|
(when loaded?
|
||||||
|
(if request-access?
|
||||||
|
[:> context-wrapper* {:is-workspace workspace?
|
||||||
|
:is-dashboard dashboard?
|
||||||
|
:is-viewer view?
|
||||||
|
:profile profile}
|
||||||
|
[:> request-access* {:file-id (:file-id info)
|
||||||
|
:team-id (:team-id info)
|
||||||
|
:is-default (:team-default info)
|
||||||
|
:is-workspace workspace?}]]
|
||||||
|
|
||||||
|
[:> exception-section* props])))))
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user