diff --git a/authentik/core/templates/user/details.html b/authentik/core/templates/user/details.html
new file mode 100644
index 000000000..b46c1f9a6
--- /dev/null
+++ b/authentik/core/templates/user/details.html
@@ -0,0 +1,26 @@
+{% load i18n %}
+
+
diff --git a/authentik/core/templates/user/settings.html b/authentik/core/templates/user/settings.html
index ef34045b8..49ee9b2b0 100644
--- a/authentik/core/templates/user/settings.html
+++ b/authentik/core/templates/user/settings.html
@@ -15,29 +15,9 @@
diff --git a/authentik/core/tests/test_views_user.py b/authentik/core/tests/test_views_user.py
index 04b5c608d..d55edd38c 100644
--- a/authentik/core/tests/test_views_user.py
+++ b/authentik/core/tests/test_views_user.py
@@ -28,3 +28,9 @@ class TestUserViews(TestCase):
self.assertEqual(
self.client.get(reverse("authentik_core:user-settings")).status_code, 200
)
+
+ def test_user_details(self):
+ """Test UserDetailsView"""
+ self.assertEqual(
+ self.client.get(reverse("authentik_core:user-details")).status_code, 200
+ )
diff --git a/authentik/core/urls.py b/authentik/core/urls.py
index e4bafb726..7a85fc585 100644
--- a/authentik/core/urls.py
+++ b/authentik/core/urls.py
@@ -7,6 +7,7 @@ urlpatterns = [
path("", shell.ShellView.as_view(), name="shell"),
# User views
path("-/user/", user.UserSettingsView.as_view(), name="user-settings"),
+ path("-/user/details/", user.UserDetailsView.as_view(), name="user-details"),
path("-/user/tokens/", user.TokenListView.as_view(), name="user-tokens"),
path(
"-/user/tokens/create/",
diff --git a/authentik/core/views/user.py b/authentik/core/views/user.py
index 1c3cdd24d..4fbb67daf 100644
--- a/authentik/core/views/user.py
+++ b/authentik/core/views/user.py
@@ -11,6 +11,7 @@ from django.http.response import HttpResponse
from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from django.views.generic import ListView, UpdateView
+from django.views.generic.base import TemplateView
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
from guardian.shortcuts import get_objects_for_user
@@ -26,14 +27,20 @@ from authentik.flows.models import Flow, FlowDesignation
from authentik.lib.views import CreateAssignPermView
-class UserSettingsView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
- """Update User settings"""
+class UserSettingsView(TemplateView):
+ """Multiple SiteShells for user details and all stages"""
template_name = "user/settings.html"
+
+
+class UserDetailsView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
+ """Update User details"""
+
+ template_name = "user/details.html"
form_class = UserDetailForm
success_message = _("Successfully updated user.")
- success_url = reverse_lazy("authentik_core:user-settings")
+ success_url = reverse_lazy("authentik_core:user-details")
def get_object(self):
return self.request.user
diff --git a/web/src/pages/generic/SiteShell.ts b/web/src/pages/generic/SiteShell.ts
index 47daf58c0..a9ae5c1ee 100644
--- a/web/src/pages/generic/SiteShell.ts
+++ b/web/src/pages/generic/SiteShell.ts
@@ -63,6 +63,9 @@ export class SiteShell extends LitElement {
if (!this._url) {
return;
}
+ if (this.loading) {
+ return;
+ }
this.loading = true;
fetch(this._url)
.then((r) => {
@@ -75,6 +78,7 @@ export class SiteShell extends LitElement {
level_tag: "error",
message: gettext(`Request failed: ${r.statusText}`),
});
+ this.loading = false;
throw new SentryIgnoredError("Request failed");
})
.then((r) => r.text())