interface split (#943)
This commit is contained in:
		
							
								
								
									
										126
									
								
								.github/workflows/ci-main.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										126
									
								
								.github/workflows/ci-main.yml
									
									
									
									
										vendored
									
									
								
							| @ -25,14 +25,14 @@ jobs: | |||||||
|       - uses: actions/setup-python@v2 |       - uses: actions/setup-python@v2 | ||||||
|         with: |         with: | ||||||
|           python-version: '3.9' |           python-version: '3.9' | ||||||
|       - id: cache-pipenv |       # - id: cache-pipenv | ||||||
|         uses: actions/cache@v2.1.6 |       #   uses: actions/cache@v2.1.6 | ||||||
|         with: |       #   with: | ||||||
|           path: ~/.local/share/virtualenvs |       #     path: ~/.local/share/virtualenvs | ||||||
|           key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} |       #     key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} | ||||||
|       - name: prepare |       - name: prepare | ||||||
|         env: |         # env: | ||||||
|           INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} |         #   INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} | ||||||
|         run: scripts/ci_prepare.sh |         run: scripts/ci_prepare.sh | ||||||
|       - name: run pylint |       - name: run pylint | ||||||
|         run: pipenv run pylint authentik tests lifecycle |         run: pipenv run pylint authentik tests lifecycle | ||||||
| @ -43,14 +43,14 @@ jobs: | |||||||
|       - uses: actions/setup-python@v2 |       - uses: actions/setup-python@v2 | ||||||
|         with: |         with: | ||||||
|           python-version: '3.9' |           python-version: '3.9' | ||||||
|       - id: cache-pipenv |       # - id: cache-pipenv | ||||||
|         uses: actions/cache@v2.1.6 |       #   uses: actions/cache@v2.1.6 | ||||||
|         with: |       #   with: | ||||||
|           path: ~/.local/share/virtualenvs |       #     path: ~/.local/share/virtualenvs | ||||||
|           key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} |       #     key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} | ||||||
|       - name: prepare |       - name: prepare | ||||||
|         env: |         # env: | ||||||
|           INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} |         #   INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} | ||||||
|         run: scripts/ci_prepare.sh |         run: scripts/ci_prepare.sh | ||||||
|       - name: run black |       - name: run black | ||||||
|         run: pipenv run black --check authentik tests lifecycle |         run: pipenv run black --check authentik tests lifecycle | ||||||
| @ -61,14 +61,14 @@ jobs: | |||||||
|       - uses: actions/setup-python@v2 |       - uses: actions/setup-python@v2 | ||||||
|         with: |         with: | ||||||
|           python-version: '3.9' |           python-version: '3.9' | ||||||
|       - id: cache-pipenv |       # - id: cache-pipenv | ||||||
|         uses: actions/cache@v2.1.6 |       #   uses: actions/cache@v2.1.6 | ||||||
|         with: |       #   with: | ||||||
|           path: ~/.local/share/virtualenvs |       #     path: ~/.local/share/virtualenvs | ||||||
|           key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} |       #     key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} | ||||||
|       - name: prepare |       - name: prepare | ||||||
|         env: |         # env: | ||||||
|           INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} |         #   INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} | ||||||
|         run: scripts/ci_prepare.sh |         run: scripts/ci_prepare.sh | ||||||
|       - name: run isort |       - name: run isort | ||||||
|         run: pipenv run isort --check authentik tests lifecycle |         run: pipenv run isort --check authentik tests lifecycle | ||||||
| @ -79,14 +79,14 @@ jobs: | |||||||
|       - uses: actions/setup-python@v2 |       - uses: actions/setup-python@v2 | ||||||
|         with: |         with: | ||||||
|           python-version: '3.9' |           python-version: '3.9' | ||||||
|       - id: cache-pipenv |       # - id: cache-pipenv | ||||||
|         uses: actions/cache@v2.1.6 |       #   uses: actions/cache@v2.1.6 | ||||||
|         with: |       #   with: | ||||||
|           path: ~/.local/share/virtualenvs |       #     path: ~/.local/share/virtualenvs | ||||||
|           key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} |       #     key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} | ||||||
|       - name: prepare |       - name: prepare | ||||||
|         env: |         # env: | ||||||
|           INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} |         #   INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} | ||||||
|         run: scripts/ci_prepare.sh |         run: scripts/ci_prepare.sh | ||||||
|       - name: run bandit |       - name: run bandit | ||||||
|         run: pipenv run bandit -r authentik tests lifecycle |         run: pipenv run bandit -r authentik tests lifecycle | ||||||
| @ -113,14 +113,14 @@ jobs: | |||||||
|       - uses: actions/setup-python@v2 |       - uses: actions/setup-python@v2 | ||||||
|         with: |         with: | ||||||
|           python-version: '3.9' |           python-version: '3.9' | ||||||
|       - id: cache-pipenv |       # - id: cache-pipenv | ||||||
|         uses: actions/cache@v2.1.6 |       #   uses: actions/cache@v2.1.6 | ||||||
|         with: |       #   with: | ||||||
|           path: ~/.local/share/virtualenvs |       #     path: ~/.local/share/virtualenvs | ||||||
|           key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} |       #     key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} | ||||||
|       - name: prepare |       - name: prepare | ||||||
|         env: |         # env: | ||||||
|           INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} |         #   INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} | ||||||
|         run: scripts/ci_prepare.sh |         run: scripts/ci_prepare.sh | ||||||
|       - name: run migrations |       - name: run migrations | ||||||
|         run: pipenv run python -m lifecycle.migrate |         run: pipenv run python -m lifecycle.migrate | ||||||
| @ -138,14 +138,14 @@ jobs: | |||||||
|           # Copy current, latest config to local |           # Copy current, latest config to local | ||||||
|           cp authentik/lib/default.yml local.env.yml |           cp authentik/lib/default.yml local.env.yml | ||||||
|           git checkout $(git describe --abbrev=0 --match 'version/*') |           git checkout $(git describe --abbrev=0 --match 'version/*') | ||||||
|       - id: cache-pipenv |       # - id: cache-pipenv | ||||||
|         uses: actions/cache@v2.1.6 |       #   uses: actions/cache@v2.1.6 | ||||||
|         with: |       #   with: | ||||||
|           path: ~/.local/share/virtualenvs |       #     path: ~/.local/share/virtualenvs | ||||||
|           key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} |       #     key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} | ||||||
|       - name: prepare |       - name: prepare | ||||||
|         env: |         # env: | ||||||
|           INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} |         #   INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} | ||||||
|         run: scripts/ci_prepare.sh |         run: scripts/ci_prepare.sh | ||||||
|       - name: run migrations to stable |       - name: run migrations to stable | ||||||
|         run: pipenv run python -m lifecycle.migrate |         run: pipenv run python -m lifecycle.migrate | ||||||
| @ -168,14 +168,14 @@ jobs: | |||||||
|       - uses: actions/setup-python@v2 |       - uses: actions/setup-python@v2 | ||||||
|         with: |         with: | ||||||
|           python-version: '3.9' |           python-version: '3.9' | ||||||
|       - id: cache-pipenv |       # - id: cache-pipenv | ||||||
|         uses: actions/cache@v2.1.6 |       #   uses: actions/cache@v2.1.6 | ||||||
|         with: |       #   with: | ||||||
|           path: ~/.local/share/virtualenvs |       #     path: ~/.local/share/virtualenvs | ||||||
|           key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} |       #     key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} | ||||||
|       - name: prepare |       - name: prepare | ||||||
|         env: |         # env: | ||||||
|           INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} |         #   INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} | ||||||
|         run: scripts/ci_prepare.sh |         run: scripts/ci_prepare.sh | ||||||
|       - uses: testspace-com/setup-testspace@v1 |       - uses: testspace-com/setup-testspace@v1 | ||||||
|         with: |         with: | ||||||
| @ -197,14 +197,14 @@ jobs: | |||||||
|       - uses: actions/setup-python@v2 |       - uses: actions/setup-python@v2 | ||||||
|         with: |         with: | ||||||
|           python-version: '3.9' |           python-version: '3.9' | ||||||
|       - id: cache-pipenv |       # - id: cache-pipenv | ||||||
|         uses: actions/cache@v2.1.6 |       #   uses: actions/cache@v2.1.6 | ||||||
|         with: |       #   with: | ||||||
|           path: ~/.local/share/virtualenvs |       #     path: ~/.local/share/virtualenvs | ||||||
|           key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} |       #     key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} | ||||||
|       - name: prepare |       - name: prepare | ||||||
|         env: |         # env: | ||||||
|           INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} |         #   INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} | ||||||
|         run: scripts/ci_prepare.sh |         run: scripts/ci_prepare.sh | ||||||
|       - uses: testspace-com/setup-testspace@v1 |       - uses: testspace-com/setup-testspace@v1 | ||||||
|         with: |         with: | ||||||
| @ -236,14 +236,14 @@ jobs: | |||||||
|       - uses: testspace-com/setup-testspace@v1 |       - uses: testspace-com/setup-testspace@v1 | ||||||
|         with: |         with: | ||||||
|           domain: ${{github.repository_owner}} |           domain: ${{github.repository_owner}} | ||||||
|       - id: cache-pipenv |       # - id: cache-pipenv | ||||||
|         uses: actions/cache@v2.1.6 |       #   uses: actions/cache@v2.1.6 | ||||||
|         with: |       #   with: | ||||||
|           path: ~/.local/share/virtualenvs |       #     path: ~/.local/share/virtualenvs | ||||||
|           key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} |       #     key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }} | ||||||
|       - name: prepare |       - name: prepare | ||||||
|         env: |         # env: | ||||||
|           INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} |         #   INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }} | ||||||
|         run: | |         run: | | ||||||
|           scripts/ci_prepare.sh |           scripts/ci_prepare.sh | ||||||
|           docker-compose -f tests/e2e/ci.docker-compose.yml up -d |           docker-compose -f tests/e2e/ci.docker-compose.yml up -d | ||||||
|  | |||||||
| @ -17,7 +17,6 @@ | |||||||
|         {% endblock %} |         {% endblock %} | ||||||
|         <link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}"> |         <link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}"> | ||||||
|         <script src="{% static 'dist/poly.js' %}" type="module"></script> |         <script src="{% static 'dist/poly.js' %}" type="module"></script> | ||||||
|         <script>window["polymerSkipLoadingFontRoboto"] = true;</script> |  | ||||||
|         {% block head %} |         {% block head %} | ||||||
|         {% endblock %} |         {% endblock %} | ||||||
|     </head> |     </head> | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
| {% load i18n %} | {% load i18n %} | ||||||
|  |  | ||||||
| {% block head_before %} | {% block head_before %} | ||||||
|  | {{ block.super }} | ||||||
| {% if flow.compatibility_mode %} | {% if flow.compatibility_mode %} | ||||||
| <script>ShadyDOM = { force: !navigator.webdriver };</script> | <script>ShadyDOM = { force: !navigator.webdriver };</script> | ||||||
| {% endif %} | {% endif %} | ||||||
|  | |||||||
							
								
								
									
										28
									
								
								authentik/core/templates/if/user.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								authentik/core/templates/if/user.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | {% extends "base/skeleton.html" %} | ||||||
|  |  | ||||||
|  | {% load static %} | ||||||
|  | {% load i18n %} | ||||||
|  |  | ||||||
|  | {% block head %} | ||||||
|  | <script src="{% static 'dist/UserInterface.js' %}" type="module"></script> | ||||||
|  | {% endblock %} | ||||||
|  |  | ||||||
|  | {% block body %} | ||||||
|  | <ak-message-container></ak-message-container> | ||||||
|  | <ak-interface-user> | ||||||
|  |     <section class="ak-static-page pf-c-page__main-section pf-m-no-padding-mobile pf-m-xl"> | ||||||
|  |         <div class="pf-c-empty-state" style="height: 100vh;"> | ||||||
|  |             <div class="pf-c-empty-state__content"> | ||||||
|  |                 <span class="pf-c-spinner pf-m-xl pf-c-empty-state__icon" role="progressbar" aria-valuetext="{% trans 'Loading...' %}"> | ||||||
|  |                     <span class="pf-c-spinner__clipper"></span> | ||||||
|  |                     <span class="pf-c-spinner__lead-ball"></span> | ||||||
|  |                     <span class="pf-c-spinner__tail-ball"></span> | ||||||
|  |                 </span> | ||||||
|  |                 <h1 class="pf-c-title pf-m-lg"> | ||||||
|  |                     {% trans "Loading..." %} | ||||||
|  |                 </h1> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </section> | ||||||
|  | </ak-interface-user> | ||||||
|  | {% endblock %} | ||||||
| @ -12,7 +12,7 @@ from authentik.core.views.session import EndSessionView | |||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|     path( |     path( | ||||||
|         "", |         "", | ||||||
|         login_required(RedirectView.as_view(pattern_name="authentik_core:if-admin")), |         login_required(RedirectView.as_view(pattern_name="authentik_core:if-user")), | ||||||
|         name="root-redirect", |         name="root-redirect", | ||||||
|     ), |     ), | ||||||
|     # Impersonation |     # Impersonation | ||||||
| @ -32,6 +32,11 @@ urlpatterns = [ | |||||||
|         ensure_csrf_cookie(TemplateView.as_view(template_name="if/admin.html")), |         ensure_csrf_cookie(TemplateView.as_view(template_name="if/admin.html")), | ||||||
|         name="if-admin", |         name="if-admin", | ||||||
|     ), |     ), | ||||||
|  |     path( | ||||||
|  |         "if/user/", | ||||||
|  |         ensure_csrf_cookie(TemplateView.as_view(template_name="if/user.html")), | ||||||
|  |         name="if-user", | ||||||
|  |     ), | ||||||
|     path( |     path( | ||||||
|         "if/flow/<slug:flow_slug>/", |         "if/flow/<slug:flow_slug>/", | ||||||
|         ensure_csrf_cookie(FlowInterfaceView.as_view()), |         ensure_csrf_cookie(FlowInterfaceView.as_view()), | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ from django.db.models import F, Q | |||||||
| from django.db.models import Value as V | from django.db.models import Value as V | ||||||
| from django.http.request import HttpRequest | from django.http.request import HttpRequest | ||||||
|  |  | ||||||
| from authentik import __version__ |  | ||||||
| from authentik.lib.config import CONFIG | from authentik.lib.config import CONFIG | ||||||
| from authentik.tenants.models import Tenant | from authentik.tenants.models import Tenant | ||||||
|  |  | ||||||
| @ -31,6 +30,5 @@ def context_processor(request: HttpRequest) -> dict[str, Any]: | |||||||
|     tenant = getattr(request, "tenant", DEFAULT_TENANT) |     tenant = getattr(request, "tenant", DEFAULT_TENANT) | ||||||
|     return { |     return { | ||||||
|         "tenant": tenant, |         "tenant": tenant, | ||||||
|         "ak_version": __version__, |  | ||||||
|         "footer_links": CONFIG.y("footer_links"), |         "footer_links": CONFIG.y("footer_links"), | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -52,7 +52,7 @@ class TestFlowsAuthenticator(SeleniumTestCase): | |||||||
|  |  | ||||||
|         code_stage.find_element(By.CSS_SELECTOR, "input[name=code]").send_keys(totp.token()) |         code_stage.find_element(By.CSS_SELECTOR, "input[name=code]").send_keys(totp.token()) | ||||||
|         code_stage.find_element(By.CSS_SELECTOR, "input[name=code]").send_keys(Keys.ENTER) |         code_stage.find_element(By.CSS_SELECTOR, "input[name=code]").send_keys(Keys.ENTER) | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.assert_user(USER()) |         self.assert_user(USER()) | ||||||
|  |  | ||||||
|     @retry() |     @retry() | ||||||
| @ -67,7 +67,7 @@ class TestFlowsAuthenticator(SeleniumTestCase): | |||||||
|         self.driver.get(self.url("authentik_core:if-flow", flow_slug=flow.slug)) |         self.driver.get(self.url("authentik_core:if-flow", flow_slug=flow.slug)) | ||||||
|         self.login() |         self.login() | ||||||
|  |  | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.assert_user(USER()) |         self.assert_user(USER()) | ||||||
|  |  | ||||||
|         self.driver.get( |         self.driver.get( | ||||||
| @ -112,7 +112,7 @@ class TestFlowsAuthenticator(SeleniumTestCase): | |||||||
|         self.driver.get(self.url("authentik_core:if-flow", flow_slug=flow.slug)) |         self.driver.get(self.url("authentik_core:if-flow", flow_slug=flow.slug)) | ||||||
|         self.login() |         self.login() | ||||||
|  |  | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.assert_user(USER()) |         self.assert_user(USER()) | ||||||
|  |  | ||||||
|         self.driver.get( |         self.driver.get( | ||||||
|  | |||||||
| @ -96,11 +96,11 @@ class TestFlowsEnroll(SeleniumTestCase): | |||||||
|  |  | ||||||
|         self.initial_stages() |         self.initial_stages() | ||||||
|  |  | ||||||
|         interface_admin = self.get_shadow_root("ak-interface-admin") |         interface_user = self.get_shadow_root("ak-interface-user") | ||||||
|         wait = WebDriverWait(interface_admin, self.wait_timeout) |         wait = WebDriverWait(interface_user, self.wait_timeout) | ||||||
|  |  | ||||||
|         wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "ak-sidebar"))) |         wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "ak-sidebar"))) | ||||||
|         self.driver.get(self.if_admin_url("/user")) |         self.driver.get(self.if_user_url("/user")) | ||||||
|  |  | ||||||
|         user = User.objects.get(username="foo") |         user = User.objects.get(username="foo") | ||||||
|         self.assertEqual(user.username, "foo") |         self.assertEqual(user.username, "foo") | ||||||
| @ -195,10 +195,10 @@ class TestFlowsEnroll(SeleniumTestCase): | |||||||
|  |  | ||||||
|         sleep(2) |         sleep(2) | ||||||
|         # We're now logged in |         # We're now logged in | ||||||
|         wait = WebDriverWait(self.get_shadow_root("ak-interface-admin"), self.wait_timeout) |         wait = WebDriverWait(self.get_shadow_root("ak-interface-user"), self.wait_timeout) | ||||||
|  |  | ||||||
|         wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "ak-sidebar"))) |         wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "ak-sidebar"))) | ||||||
|         self.driver.get(self.if_admin_url("/user")) |         self.driver.get(self.if_user_url("/user")) | ||||||
|  |  | ||||||
|         self.assert_user(User.objects.get(username="foo")) |         self.assert_user(User.objects.get(username="foo")) | ||||||
|  |  | ||||||
|  | |||||||
| @ -22,5 +22,5 @@ class TestFlowsLogin(SeleniumTestCase): | |||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
|         self.login() |         self.login() | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.assert_user(USER()) |         self.assert_user(USER()) | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ class TestFlowsStageSetup(SeleniumTestCase): | |||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
|         self.login() |         self.login() | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|  |  | ||||||
|         self.driver.get( |         self.driver.get( | ||||||
|             self.url( |             self.url( | ||||||
| @ -62,7 +62,7 @@ class TestFlowsStageSetup(SeleniumTestCase): | |||||||
|             Keys.ENTER |             Keys.ENTER | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         # Because USER() is cached, we need to get the user manually here |         # Because USER() is cached, we need to get the user manually here | ||||||
|         user = User.objects.get(username=USER().username) |         user = User.objects.get(username=USER().username) | ||||||
|         self.assertTrue(user.check_password(new_password)) |         self.assertTrue(user.check_password(new_password)) | ||||||
|  | |||||||
| @ -174,8 +174,8 @@ class TestSourceOAuth2(SeleniumTestCase): | |||||||
|         prompt_stage.find_element(By.CSS_SELECTOR, "input[name=username]").send_keys(Keys.ENTER) |         prompt_stage.find_element(By.CSS_SELECTOR, "input[name=username]").send_keys(Keys.ENTER) | ||||||
|  |  | ||||||
|         # Wait until we've logged in |         # Wait until we've logged in | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.driver.get(self.if_admin_url("/user")) |         self.driver.get(self.if_user_url("/user")) | ||||||
|  |  | ||||||
|         self.assert_user(User(username="foo", name="admin", email="admin@example.com")) |         self.assert_user(User(username="foo", name="admin", email="admin@example.com")) | ||||||
|  |  | ||||||
| @ -253,8 +253,8 @@ class TestSourceOAuth2(SeleniumTestCase): | |||||||
|         self.driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click() |         self.driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click() | ||||||
|  |  | ||||||
|         # Wait until we've logged in |         # Wait until we've logged in | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.driver.get(self.if_admin_url("/user")) |         self.driver.get(self.if_user_url("/user")) | ||||||
|  |  | ||||||
|         self.assert_user(User(username="foo", name="admin", email="admin@example.com")) |         self.assert_user(User(username="foo", name="admin", email="admin@example.com")) | ||||||
|  |  | ||||||
| @ -348,7 +348,7 @@ class TestSourceOAuth1(SeleniumTestCase): | |||||||
|         # Wait until we've loaded the user info page |         # Wait until we've loaded the user info page | ||||||
|         sleep(2) |         sleep(2) | ||||||
|         # Wait until we've logged in |         # Wait until we've logged in | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.driver.get(self.if_admin_url("/user")) |         self.driver.get(self.if_user_url("/user")) | ||||||
|  |  | ||||||
|         self.assert_user(User(username="example-user", name="test name", email="foo@example.com")) |         self.assert_user(User(username="example-user", name="test name", email="foo@example.com")) | ||||||
|  | |||||||
| @ -153,8 +153,8 @@ class TestSourceSAML(SeleniumTestCase): | |||||||
|         self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) |         self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) | ||||||
|  |  | ||||||
|         # Wait until we're logged in |         # Wait until we're logged in | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.driver.get(self.if_admin_url("/user")) |         self.driver.get(self.if_user_url("/user")) | ||||||
|  |  | ||||||
|         self.assert_user( |         self.assert_user( | ||||||
|             User.objects.exclude(username="akadmin") |             User.objects.exclude(username="akadmin") | ||||||
| @ -233,8 +233,8 @@ class TestSourceSAML(SeleniumTestCase): | |||||||
|         self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) |         self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) | ||||||
|  |  | ||||||
|         # Wait until we're logged in |         # Wait until we're logged in | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.driver.get(self.if_admin_url("/user")) |         self.driver.get(self.if_user_url("/user")) | ||||||
|  |  | ||||||
|         self.assert_user( |         self.assert_user( | ||||||
|             User.objects.exclude(username="akadmin") |             User.objects.exclude(username="akadmin") | ||||||
| @ -300,8 +300,8 @@ class TestSourceSAML(SeleniumTestCase): | |||||||
|         self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) |         self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) | ||||||
|  |  | ||||||
|         # Wait until we're logged in |         # Wait until we're logged in | ||||||
|         self.wait_for_url(self.if_admin_url("/library")) |         self.wait_for_url(self.if_user_url("/library")) | ||||||
|         self.driver.get(self.if_admin_url("/user")) |         self.driver.get(self.if_user_url("/user")) | ||||||
|  |  | ||||||
|         self.assert_user( |         self.assert_user( | ||||||
|             User.objects.exclude(username="akadmin") |             User.objects.exclude(username="akadmin") | ||||||
|  | |||||||
| @ -126,9 +126,9 @@ class SeleniumTestCase(StaticLiveServerTestCase): | |||||||
|         """reverse `view` with `**kwargs` into full URL using live_server_url""" |         """reverse `view` with `**kwargs` into full URL using live_server_url""" | ||||||
|         return self.live_server_url + reverse(view, kwargs=kwargs) |         return self.live_server_url + reverse(view, kwargs=kwargs) | ||||||
|  |  | ||||||
|     def if_admin_url(self, view) -> str: |     def if_user_url(self, view) -> str: | ||||||
|         """same as self.url() but show URL in shell""" |         """same as self.url() but show URL in shell""" | ||||||
|         return f"{self.live_server_url}/if/admin/#{view}" |         return f"{self.live_server_url}/if/user/#{view}" | ||||||
|  |  | ||||||
|     def get_shadow_root(self, selector: str, container: Optional[WebElement] = None) -> WebElement: |     def get_shadow_root(self, selector: str, container: Optional[WebElement] = None) -> WebElement: | ||||||
|         """Get shadow root element's inner shadowRoot""" |         """Get shadow root element's inner shadowRoot""" | ||||||
|  | |||||||
| @ -1,2 +1,4 @@ | |||||||
|  | // @ts-ignore | ||||||
|  | window["polymerSkipLoadingFontRoboto"] = true; | ||||||
| import "construct-style-sheets-polyfill"; | import "construct-style-sheets-polyfill"; | ||||||
| import "@webcomponents/webcomponentsjs"; | import "@webcomponents/webcomponentsjs"; | ||||||
|  | |||||||
| @ -87,40 +87,7 @@ export default [ | |||||||
|             clearScreen: false, |             clearScreen: false, | ||||||
|         }, |         }, | ||||||
|     }, |     }, | ||||||
|     // Main Application |     // Flow interface | ||||||
|     { |  | ||||||
|         input: "./src/interfaces/AdminInterface.ts", |  | ||||||
|         context: "window", |  | ||||||
|         output: [ |  | ||||||
|             { |  | ||||||
|                 format: "es", |  | ||||||
|                 dir: "dist", |  | ||||||
|                 sourcemap: true, |  | ||||||
|                 manualChunks: manualChunks, |  | ||||||
|                 chunkFileNames: "admin-[name].js", |  | ||||||
|             }, |  | ||||||
|         ], |  | ||||||
|         plugins: [ |  | ||||||
|             cssimport(), |  | ||||||
|             resolve({ extensions, browser: true }), |  | ||||||
|             commonjs(), |  | ||||||
|             babel({ |  | ||||||
|                 extensions, |  | ||||||
|                 babelHelpers: "runtime", |  | ||||||
|                 include: ["src/**/*"], |  | ||||||
|             }), |  | ||||||
|             replace({ |  | ||||||
|                 "process.env.NODE_ENV": JSON.stringify(isProdBuild ? "production" : "development"), |  | ||||||
|                 "preventAssignment": true, |  | ||||||
|             }), |  | ||||||
|             sourcemaps(), |  | ||||||
|             isProdBuild && terser(), |  | ||||||
|         ].filter((p) => p), |  | ||||||
|         watch: { |  | ||||||
|             clearScreen: false, |  | ||||||
|         }, |  | ||||||
|     }, |  | ||||||
|     // Flow executor |  | ||||||
|     { |     { | ||||||
|         input: "./src/interfaces/FlowInterface.ts", |         input: "./src/interfaces/FlowInterface.ts", | ||||||
|         context: "window", |         context: "window", | ||||||
| @ -153,4 +120,70 @@ export default [ | |||||||
|             clearScreen: false, |             clearScreen: false, | ||||||
|         }, |         }, | ||||||
|     }, |     }, | ||||||
|  |     // Admin interface | ||||||
|  |     { | ||||||
|  |         input: "./src/interfaces/AdminInterface.ts", | ||||||
|  |         context: "window", | ||||||
|  |         output: [ | ||||||
|  |             { | ||||||
|  |                 format: "es", | ||||||
|  |                 dir: "dist", | ||||||
|  |                 sourcemap: true, | ||||||
|  |                 manualChunks: manualChunks, | ||||||
|  |                 chunkFileNames: "admin-[name].js", | ||||||
|  |             }, | ||||||
|  |         ], | ||||||
|  |         plugins: [ | ||||||
|  |             cssimport(), | ||||||
|  |             resolve({ extensions, browser: true }), | ||||||
|  |             commonjs(), | ||||||
|  |             babel({ | ||||||
|  |                 extensions, | ||||||
|  |                 babelHelpers: "runtime", | ||||||
|  |                 include: ["src/**/*"], | ||||||
|  |             }), | ||||||
|  |             replace({ | ||||||
|  |                 "process.env.NODE_ENV": JSON.stringify(isProdBuild ? "production" : "development"), | ||||||
|  |                 "preventAssignment": true, | ||||||
|  |             }), | ||||||
|  |             sourcemaps(), | ||||||
|  |             isProdBuild && terser(), | ||||||
|  |         ].filter((p) => p), | ||||||
|  |         watch: { | ||||||
|  |             clearScreen: false, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  |     // User interface | ||||||
|  |     { | ||||||
|  |         input: "./src/interfaces/UserInterface.ts", | ||||||
|  |         context: "window", | ||||||
|  |         output: [ | ||||||
|  |             { | ||||||
|  |                 format: "es", | ||||||
|  |                 dir: "dist", | ||||||
|  |                 sourcemap: true, | ||||||
|  |                 manualChunks: manualChunks, | ||||||
|  |                 chunkFileNames: "user-[name].js", | ||||||
|  |             }, | ||||||
|  |         ], | ||||||
|  |         plugins: [ | ||||||
|  |             cssimport(), | ||||||
|  |             resolve({ extensions, browser: true }), | ||||||
|  |             commonjs(), | ||||||
|  |             babel({ | ||||||
|  |                 extensions, | ||||||
|  |                 babelHelpers: "runtime", | ||||||
|  |                 include: ["src/**/*"], | ||||||
|  |             }), | ||||||
|  |             replace({ | ||||||
|  |                 "process.env.NODE_ENV": JSON.stringify(isProdBuild ? "production" : "development"), | ||||||
|  |                 "preventAssignment": true, | ||||||
|  |             }), | ||||||
|  |             sourcemaps(), | ||||||
|  |             isProdBuild && terser(), | ||||||
|  |         ].filter((p) => p), | ||||||
|  |         watch: { | ||||||
|  |             clearScreen: false, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
| ]; | ]; | ||||||
|  | |||||||
| @ -83,9 +83,6 @@ html > form > input { | |||||||
|     color: var(--pf-global--danger-color--100); |     color: var(--pf-global--danger-color--100); | ||||||
| } | } | ||||||
|  |  | ||||||
| body { |  | ||||||
|     background-color: var(--ak-dark-background) !important; |  | ||||||
| } |  | ||||||
| .ak-static-page h1 { | .ak-static-page h1 { | ||||||
|     color: var(--ak-dark-foreground); |     color: var(--ak-dark-foreground); | ||||||
| } | } | ||||||
| @ -99,6 +96,9 @@ body { | |||||||
| } | } | ||||||
|  |  | ||||||
| @media (prefers-color-scheme: dark) { | @media (prefers-color-scheme: dark) { | ||||||
|  |     body { | ||||||
|  |         background-color: var(--ak-dark-background) !important; | ||||||
|  |     } | ||||||
|     :root { |     :root { | ||||||
|         --pf-global--Color--100: var(--ak-dark-foreground); |         --pf-global--Color--100: var(--ak-dark-foreground); | ||||||
|         --pf-c-page__main-section--m-light--BackgroundColor: var(--ak-dark-background-darker); |         --pf-c-page__main-section--m-light--BackgroundColor: var(--ak-dark-background-darker); | ||||||
|  | |||||||
| @ -8,7 +8,6 @@ import { | |||||||
|     TemplateResult, |     TemplateResult, | ||||||
| } from "lit-element"; | } from "lit-element"; | ||||||
| import { Route } from "./Route"; | import { Route } from "./Route"; | ||||||
| import { ROUTES } from "../../routes"; |  | ||||||
| import { RouteMatch } from "./RouteMatch"; | import { RouteMatch } from "./RouteMatch"; | ||||||
| import AKGlobal from "../../authentik.css"; | import AKGlobal from "../../authentik.css"; | ||||||
|  |  | ||||||
| @ -45,6 +44,9 @@ export class RouterOutlet extends LitElement { | |||||||
|     @property() |     @property() | ||||||
|     defaultUrl?: string; |     defaultUrl?: string; | ||||||
|  |  | ||||||
|  |     @property({ attribute: false }) | ||||||
|  |     routes: Route[] = []; | ||||||
|  |  | ||||||
|     static get styles(): CSSResult[] { |     static get styles(): CSSResult[] { | ||||||
|         return [ |         return [ | ||||||
|             AKGlobal, |             AKGlobal, | ||||||
| @ -59,8 +61,6 @@ export class RouterOutlet extends LitElement { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 *:first-child { |                 *:first-child { | ||||||
|                     height: 100%; |  | ||||||
|                     display: flex; |  | ||||||
|                     flex-direction: column; |                     flex-direction: column; | ||||||
|                 } |                 } | ||||||
|             `, |             `, | ||||||
| @ -90,7 +90,7 @@ export class RouterOutlet extends LitElement { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         let matchedRoute: RouteMatch | null = null; |         let matchedRoute: RouteMatch | null = null; | ||||||
|         ROUTES.some((route) => { |         this.routes.some((route) => { | ||||||
|             const match = route.url.exec(activeUrl); |             const match = route.url.exec(activeUrl); | ||||||
|             if (match != null) { |             if (match != null) { | ||||||
|                 matchedRoute = new RouteMatch(route); |                 matchedRoute = new RouteMatch(route); | ||||||
|  | |||||||
| @ -33,6 +33,7 @@ import { | |||||||
| import { AdminApi, Version } from "@goauthentik/api"; | import { AdminApi, Version } from "@goauthentik/api"; | ||||||
| import { DEFAULT_CONFIG } from "../api/Config"; | import { DEFAULT_CONFIG } from "../api/Config"; | ||||||
| import { WebsocketClient } from "../common/ws"; | import { WebsocketClient } from "../common/ws"; | ||||||
|  | import { ROUTES } from "../routesAdmin"; | ||||||
|  |  | ||||||
| @customElement("ak-interface-admin") | @customElement("ak-interface-admin") | ||||||
| export class AdminInterface extends LitElement { | export class AdminInterface extends LitElement { | ||||||
| @ -110,7 +111,8 @@ export class AdminInterface extends LitElement { | |||||||
|                                         class="pf-c-page__main" |                                         class="pf-c-page__main" | ||||||
|                                         tabindex="-1" |                                         tabindex="-1" | ||||||
|                                         id="main-content" |                                         id="main-content" | ||||||
|                                         defaultUrl="/library" |                                         defaultUrl="/administration/overview" | ||||||
|  |                                         .routes=${ROUTES} | ||||||
|                                     > |                                     > | ||||||
|                                     </ak-router-outlet> |                                     </ak-router-outlet> | ||||||
|                                 </main> |                                 </main> | ||||||
| @ -135,9 +137,11 @@ export class AdminInterface extends LitElement { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     renderSidebarItems(): TemplateResult { |     renderSidebarItems(): TemplateResult { | ||||||
|         const superUserCondition = () => { |         me().then((u) => { | ||||||
|             return me().then((u) => u.user.isSuperuser || false); |             if (!u.user.isSuperuser) { | ||||||
|         }; |                 window.location.assign("/if/user"); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|         return html` |         return html` | ||||||
|             ${until( |             ${until( | ||||||
|                 this.version.then((version) => { |                 this.version.then((version) => { | ||||||
| @ -167,19 +171,16 @@ export class AdminInterface extends LitElement { | |||||||
|                     return html``; |                     return html``; | ||||||
|                 }), |                 }), | ||||||
|             )} |             )} | ||||||
|             <ak-sidebar-item path="/library"> |             <ak-sidebar-item path="/if/user/" ?isAbsoluteLink=${true} ?highlight=${true}> | ||||||
|                 <span slot="label">${t`Library`}</span> |                 <span slot="label">${t`Go to user interface`}</span> | ||||||
|             </ak-sidebar-item> |             </ak-sidebar-item> | ||||||
|             <ak-sidebar-item .condition=${superUserCondition}> |             <ak-sidebar-item path="/administration/overview"> | ||||||
|                 <span slot="label">${t`Monitor`}</span> |                 <span slot="label">${t`Overview`}</span> | ||||||
|                 <ak-sidebar-item path="/administration/overview"> |  | ||||||
|                     <span slot="label">${t`Overview`}</span> |  | ||||||
|                 </ak-sidebar-item> |  | ||||||
|                 <ak-sidebar-item path="/administration/system-tasks"> |  | ||||||
|                     <span slot="label">${t`System Tasks`}</span> |  | ||||||
|                 </ak-sidebar-item> |  | ||||||
|             </ak-sidebar-item> |             </ak-sidebar-item> | ||||||
|             <ak-sidebar-item .condition=${superUserCondition}> |             <ak-sidebar-item path="/administration/system-tasks"> | ||||||
|  |                 <span slot="label">${t`System Tasks`}</span> | ||||||
|  |             </ak-sidebar-item> | ||||||
|  |             <ak-sidebar-item> | ||||||
|                 <span slot="label">${t`Resources`}</span> |                 <span slot="label">${t`Resources`}</span> | ||||||
|                 <ak-sidebar-item |                 <ak-sidebar-item | ||||||
|                     path="/core/applications" |                     path="/core/applications" | ||||||
| @ -203,7 +204,7 @@ export class AdminInterface extends LitElement { | |||||||
|                     <span slot="label">${t`Tenants`}</span> |                     <span slot="label">${t`Tenants`}</span> | ||||||
|                 </ak-sidebar-item> |                 </ak-sidebar-item> | ||||||
|             </ak-sidebar-item> |             </ak-sidebar-item> | ||||||
|             <ak-sidebar-item .condition=${superUserCondition}> |             <ak-sidebar-item> | ||||||
|                 <span slot="label">${t`Outposts`}</span> |                 <span slot="label">${t`Outposts`}</span> | ||||||
|                 <ak-sidebar-item path="/outpost/outposts"> |                 <ak-sidebar-item path="/outpost/outposts"> | ||||||
|                     <span slot="label">${t`Outposts`}</span> |                     <span slot="label">${t`Outposts`}</span> | ||||||
| @ -212,7 +213,7 @@ export class AdminInterface extends LitElement { | |||||||
|                     <span slot="label">${t`Integrations`}</span> |                     <span slot="label">${t`Integrations`}</span> | ||||||
|                 </ak-sidebar-item> |                 </ak-sidebar-item> | ||||||
|             </ak-sidebar-item> |             </ak-sidebar-item> | ||||||
|             <ak-sidebar-item .condition=${superUserCondition}> |             <ak-sidebar-item> | ||||||
|                 <span slot="label">${t`Events`}</span> |                 <span slot="label">${t`Events`}</span> | ||||||
|                 <ak-sidebar-item |                 <ak-sidebar-item | ||||||
|                     path="/events/log" |                     path="/events/log" | ||||||
| @ -227,7 +228,7 @@ export class AdminInterface extends LitElement { | |||||||
|                     <span slot="label">${t`Notification Transports`}</span> |                     <span slot="label">${t`Notification Transports`}</span> | ||||||
|                 </ak-sidebar-item> |                 </ak-sidebar-item> | ||||||
|             </ak-sidebar-item> |             </ak-sidebar-item> | ||||||
|             <ak-sidebar-item .condition=${superUserCondition}> |             <ak-sidebar-item> | ||||||
|                 <span slot="label">${t`Customisation`}</span> |                 <span slot="label">${t`Customisation`}</span> | ||||||
|                 <ak-sidebar-item path="/policy/policies"> |                 <ak-sidebar-item path="/policy/policies"> | ||||||
|                     <span slot="label">${t`Policies`}</span> |                     <span slot="label">${t`Policies`}</span> | ||||||
| @ -242,7 +243,7 @@ export class AdminInterface extends LitElement { | |||||||
|                     <span slot="label">${t`Property Mappings`}</span> |                     <span slot="label">${t`Property Mappings`}</span> | ||||||
|                 </ak-sidebar-item> |                 </ak-sidebar-item> | ||||||
|             </ak-sidebar-item> |             </ak-sidebar-item> | ||||||
|             <ak-sidebar-item .condition=${superUserCondition}> |             <ak-sidebar-item> | ||||||
|                 <span slot="label">${t`Flows`}</span> |                 <span slot="label">${t`Flows`}</span> | ||||||
|                 <ak-sidebar-item |                 <ak-sidebar-item | ||||||
|                     path="/flow/flows" |                     path="/flow/flows" | ||||||
| @ -260,7 +261,7 @@ export class AdminInterface extends LitElement { | |||||||
|                     <span slot="label">${t`Invitations`}</span> |                     <span slot="label">${t`Invitations`}</span> | ||||||
|                 </ak-sidebar-item> |                 </ak-sidebar-item> | ||||||
|             </ak-sidebar-item> |             </ak-sidebar-item> | ||||||
|             <ak-sidebar-item .condition=${superUserCondition}> |             <ak-sidebar-item> | ||||||
|                 <span slot="label">${t`Identity & Cryptography`}</span> |                 <span slot="label">${t`Identity & Cryptography`}</span> | ||||||
|                 <ak-sidebar-item |                 <ak-sidebar-item | ||||||
|                     path="/identity/users" |                     path="/identity/users" | ||||||
|  | |||||||
							
								
								
									
										176
									
								
								web/src/interfaces/UserInterface.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								web/src/interfaces/UserInterface.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,176 @@ | |||||||
|  | import "../elements/messages/MessageContainer"; | ||||||
|  | import { | ||||||
|  |     css, | ||||||
|  |     CSSResult, | ||||||
|  |     customElement, | ||||||
|  |     html, | ||||||
|  |     LitElement, | ||||||
|  |     property, | ||||||
|  |     TemplateResult, | ||||||
|  | } from "lit-element"; | ||||||
|  | import { me } from "../api/Users"; | ||||||
|  | import "./locale"; | ||||||
|  | import "../elements/sidebar/SidebarItem"; | ||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||||
|  | import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||||
|  | import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||||||
|  | import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css"; | ||||||
|  | import AKGlobal from "../authentik.css"; | ||||||
|  |  | ||||||
|  | import "../elements/router/RouterOutlet"; | ||||||
|  | import "../elements/messages/MessageContainer"; | ||||||
|  | import "../elements/notifications/NotificationDrawer"; | ||||||
|  | import "../elements/sidebar/Sidebar"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { | ||||||
|  |     EVENT_API_DRAWER_TOGGLE, | ||||||
|  |     EVENT_NOTIFICATION_DRAWER_TOGGLE, | ||||||
|  |     EVENT_SIDEBAR_TOGGLE, | ||||||
|  |     VERSION, | ||||||
|  | } from "../constants"; | ||||||
|  | import { AdminApi, Version } from "@goauthentik/api"; | ||||||
|  | import { DEFAULT_CONFIG } from "../api/Config"; | ||||||
|  | import { WebsocketClient } from "../common/ws"; | ||||||
|  | import { ROUTES } from "../routesUser"; | ||||||
|  |  | ||||||
|  | @customElement("ak-interface-user") | ||||||
|  | export class UserInterface extends LitElement { | ||||||
|  |     @property({ type: Boolean }) | ||||||
|  |     sidebarOpen = true; | ||||||
|  |  | ||||||
|  |     @property({ type: Boolean }) | ||||||
|  |     notificationOpen = false; | ||||||
|  |  | ||||||
|  |     @property({ type: Boolean }) | ||||||
|  |     apiDrawerOpen = false; | ||||||
|  |  | ||||||
|  |     ws: WebsocketClient; | ||||||
|  |  | ||||||
|  |     private version: Promise<Version>; | ||||||
|  |  | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return [ | ||||||
|  |             PFBase, | ||||||
|  |             PFPage, | ||||||
|  |             PFButton, | ||||||
|  |             PFDrawer, | ||||||
|  |             AKGlobal, | ||||||
|  |             css` | ||||||
|  |                 .pf-c-page__main, | ||||||
|  |                 .pf-c-drawer__content, | ||||||
|  |                 .pf-c-page__drawer { | ||||||
|  |                     z-index: auto !important; | ||||||
|  |                 } | ||||||
|  |                 .display-none { | ||||||
|  |                     display: none; | ||||||
|  |                 } | ||||||
|  |             `, | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     constructor() { | ||||||
|  |         super(); | ||||||
|  |         this.ws = new WebsocketClient(); | ||||||
|  |         this.sidebarOpen = window.innerWidth >= 1280; | ||||||
|  |         window.addEventListener("resize", () => { | ||||||
|  |             this.sidebarOpen = window.innerWidth >= 1280; | ||||||
|  |         }); | ||||||
|  |         window.addEventListener(EVENT_SIDEBAR_TOGGLE, () => { | ||||||
|  |             this.sidebarOpen = !this.sidebarOpen; | ||||||
|  |         }); | ||||||
|  |         window.addEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, () => { | ||||||
|  |             this.notificationOpen = !this.notificationOpen; | ||||||
|  |         }); | ||||||
|  |         window.addEventListener(EVENT_API_DRAWER_TOGGLE, () => { | ||||||
|  |             this.apiDrawerOpen = !this.apiDrawerOpen; | ||||||
|  |         }); | ||||||
|  |         this.version = new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         return html` <div class="pf-c-page"> | ||||||
|  |             <ak-sidebar | ||||||
|  |                 class="pf-c-page__sidebar ${this.sidebarOpen ? "pf-m-expanded" : "pf-m-collapsed"}" | ||||||
|  |             > | ||||||
|  |                 ${this.renderSidebarItems()} | ||||||
|  |             </ak-sidebar> | ||||||
|  |             <div class="pf-c-page__drawer"> | ||||||
|  |                 <div | ||||||
|  |                     class="pf-c-drawer ${this.notificationOpen || this.apiDrawerOpen | ||||||
|  |                         ? "pf-m-expanded" | ||||||
|  |                         : "pf-m-collapsed"}" | ||||||
|  |                 > | ||||||
|  |                     <div class="pf-c-drawer__main"> | ||||||
|  |                         <div class="pf-c-drawer__content"> | ||||||
|  |                             <div class="pf-c-drawer__body"> | ||||||
|  |                                 <main class="pf-c-page__main"> | ||||||
|  |                                     <ak-router-outlet | ||||||
|  |                                         role="main" | ||||||
|  |                                         class="pf-c-page__main" | ||||||
|  |                                         tabindex="-1" | ||||||
|  |                                         id="main-content" | ||||||
|  |                                         defaultUrl="/library" | ||||||
|  |                                         .routes=${ROUTES} | ||||||
|  |                                     > | ||||||
|  |                                     </ak-router-outlet> | ||||||
|  |                                 </main> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                         <ak-notification-drawer | ||||||
|  |                             class="pf-c-drawer__panel pf-m-width-33 ${this.notificationOpen | ||||||
|  |                                 ? "" | ||||||
|  |                                 : "display-none"}" | ||||||
|  |                             ?hidden=${!this.notificationOpen} | ||||||
|  |                         ></ak-notification-drawer> | ||||||
|  |                         <ak-api-drawer | ||||||
|  |                             class="pf-c-drawer__panel pf-m-width-33 ${this.apiDrawerOpen | ||||||
|  |                                 ? "" | ||||||
|  |                                 : "display-none"}" | ||||||
|  |                             ?hidden=${!this.apiDrawerOpen} | ||||||
|  |                         ></ak-api-drawer> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderSidebarItems(): TemplateResult { | ||||||
|  |         return html` | ||||||
|  |             ${until( | ||||||
|  |                 this.version.then((version) => { | ||||||
|  |                     if (version.versionCurrent !== VERSION) { | ||||||
|  |                         return html`<ak-sidebar-item ?highlight=${true}> | ||||||
|  |                             <span slot="label" | ||||||
|  |                                 >${t`A newer version of the frontend is available.`}</span | ||||||
|  |                             > | ||||||
|  |                         </ak-sidebar-item>`; | ||||||
|  |                     } | ||||||
|  |                     return html``; | ||||||
|  |                 }), | ||||||
|  |             )} | ||||||
|  |             ${until( | ||||||
|  |                 me().then((u) => { | ||||||
|  |                     if (u.original) { | ||||||
|  |                         return html`<ak-sidebar-item | ||||||
|  |                             ?highlight=${true} | ||||||
|  |                             ?isAbsoluteLink=${true} | ||||||
|  |                             path=${`/-/impersonation/end/?back=${window.location.pathname}%23${window.location.hash}`} | ||||||
|  |                         > | ||||||
|  |                             <span slot="label" | ||||||
|  |                                 >${t`You're currently impersonating ${u.user.username}. Click to stop.`}</span | ||||||
|  |                             > | ||||||
|  |                         </ak-sidebar-item>`; | ||||||
|  |                     } | ||||||
|  |                     return html``; | ||||||
|  |                 }), | ||||||
|  |             )} | ||||||
|  |             <ak-sidebar-item path="/if/admin" ?isAbsoluteLink=${true} ?highlight=${true}> | ||||||
|  |                 <span slot="label">${t`Go to admin interface`}</span> | ||||||
|  |             </ak-sidebar-item> | ||||||
|  |             <ak-sidebar-item path="/library"> | ||||||
|  |                 <span slot="label">${t`Library`}</span> | ||||||
|  |             </ak-sidebar-item> | ||||||
|  |         `; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,39 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="en"> |  | ||||||
|     <head> |  | ||||||
|         <meta charset="UTF-8" /> |  | ||||||
|         <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/patternfly-base.css" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/page.css" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/empty-state.css" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/spinner.css" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/authentik.css" /> |  | ||||||
|         <script src="/static/dist/poly.js" type="module"></script> |  | ||||||
|         <script> |  | ||||||
|             window["polymerSkipLoadingFontRoboto"] = true; |  | ||||||
|         </script> |  | ||||||
|         <script src="/static/dist/AdminInterface.js" type="module"></script> |  | ||||||
|         <title>authentik</title> |  | ||||||
|     </head> |  | ||||||
|     <body> |  | ||||||
|         <ak-message-container></ak-message-container> |  | ||||||
|         <ak-interface-admin> |  | ||||||
|             <section class="ak-static-page pf-c-page__main-section pf-m-no-padding-mobile pf-m-xl"> |  | ||||||
|                 <div class="pf-c-empty-state" style="height: 100vh"> |  | ||||||
|                     <div class="pf-c-empty-state__content"> |  | ||||||
|                         <span |  | ||||||
|                             class="pf-c-spinner pf-m-xl pf-c-empty-state__icon" |  | ||||||
|                             role="progressbar" |  | ||||||
|                             aria-valuetext="Loading..." |  | ||||||
|                         > |  | ||||||
|                             <span class="pf-c-spinner__clipper"></span> |  | ||||||
|                             <span class="pf-c-spinner__lead-ball"></span> |  | ||||||
|                             <span class="pf-c-spinner__tail-ball"></span> |  | ||||||
|                         </span> |  | ||||||
|                         <h1 class="pf-c-title pf-m-lg">Loading...</h1> |  | ||||||
|                     </div> |  | ||||||
|                 </div> |  | ||||||
|             </section> |  | ||||||
|         </ak-interface-admin> |  | ||||||
|     </body> |  | ||||||
| </html> |  | ||||||
| @ -1,40 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="en"> |  | ||||||
|     <head> |  | ||||||
|         <meta charset="UTF-8" /> |  | ||||||
|         <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/patternfly-base.css" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/page.css" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/empty-state.css" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/spinner.css" /> |  | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/authentik.css" /> |  | ||||||
|         <script> |  | ||||||
|             ShadyDOM = { force: !navigator.webdriver }; |  | ||||||
|             window["polymerSkipLoadingFontRoboto"] = true; |  | ||||||
|         </script> |  | ||||||
|         <script src="/static/dist/poly.js" type="module"></script> |  | ||||||
|         <script src="/static/dist/FlowInterface.js" type="module"></script> |  | ||||||
|         <title>authentik</title> |  | ||||||
|     </head> |  | ||||||
|     <body> |  | ||||||
|         <ak-message-container></ak-message-container> |  | ||||||
|         <ak-flow-executor> |  | ||||||
|             <section class="ak-static-page pf-c-page__main-section pf-m-no-padding-mobile pf-m-xl"> |  | ||||||
|                 <div class="pf-c-empty-state" style="height: 100vh"> |  | ||||||
|                     <div class="pf-c-empty-state__content"> |  | ||||||
|                         <span |  | ||||||
|                             class="pf-c-spinner pf-m-xl pf-c-empty-state__icon" |  | ||||||
|                             role="progressbar" |  | ||||||
|                             aria-valuetext="Loading..." |  | ||||||
|                         > |  | ||||||
|                             <span class="pf-c-spinner__clipper"></span> |  | ||||||
|                             <span class="pf-c-spinner__lead-ball"></span> |  | ||||||
|                             <span class="pf-c-spinner__tail-ball"></span> |  | ||||||
|                         </span> |  | ||||||
|                         <h1 class="pf-c-title pf-m-lg">Loading...</h1> |  | ||||||
|                     </div> |  | ||||||
|                 </div> |  | ||||||
|             </section> |  | ||||||
|         </ak-flow-executor> |  | ||||||
|     </body> |  | ||||||
| </html> |  | ||||||
| @ -34,6 +34,7 @@ msgid "8 digits, not compatible with apps like Google Authenticator" | |||||||
| msgstr "8 digits, not compatible with apps like Google Authenticator" | msgstr "8 digits, not compatible with apps like Google Authenticator" | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts | #: src/interfaces/AdminInterface.ts | ||||||
|  | #: src/interfaces/UserInterface.ts | ||||||
| msgid "A newer version of the frontend is available." | msgid "A newer version of the frontend is available." | ||||||
| msgstr "A newer version of the frontend is available." | msgstr "A newer version of the frontend is available." | ||||||
|  |  | ||||||
| @ -167,6 +168,10 @@ msgstr "Additional group DN, prepended to the Base DN." | |||||||
| msgid "Additional user DN, prepended to the Base DN." | msgid "Additional user DN, prepended to the Base DN." | ||||||
| msgstr "Additional user DN, prepended to the Base DN." | msgstr "Additional user DN, prepended to the Base DN." | ||||||
|  |  | ||||||
|  | #:  | ||||||
|  | #~ msgid "Admin" | ||||||
|  | #~ msgstr "Admin" | ||||||
|  |  | ||||||
| #: src/pages/providers/oauth2/OAuth2ProviderForm.ts | #: src/pages/providers/oauth2/OAuth2ProviderForm.ts | ||||||
| #: src/pages/providers/proxy/ProxyProviderForm.ts | #: src/pages/providers/proxy/ProxyProviderForm.ts | ||||||
| #: src/pages/providers/saml/SAMLProviderForm.ts | #: src/pages/providers/saml/SAMLProviderForm.ts | ||||||
| @ -282,6 +287,7 @@ msgstr "Application(s)" | |||||||
| #: src/pages/LibraryPage.ts | #: src/pages/LibraryPage.ts | ||||||
| #: src/pages/applications/ApplicationListPage.ts | #: src/pages/applications/ApplicationListPage.ts | ||||||
| #: src/pages/outposts/OutpostForm.ts | #: src/pages/outposts/OutpostForm.ts | ||||||
|  | #: src/user/LibraryPage.ts | ||||||
| msgid "Applications" | msgid "Applications" | ||||||
| msgstr "Applications" | msgstr "Applications" | ||||||
|  |  | ||||||
| @ -381,6 +387,7 @@ msgstr "Authentication flow" | |||||||
|  |  | ||||||
| #: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts | #: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Authenticator" | msgid "Authenticator" | ||||||
| msgstr "Authenticator" | msgstr "Authenticator" | ||||||
|  |  | ||||||
| @ -602,6 +609,7 @@ msgid "Certificates" | |||||||
| msgstr "Certificates" | msgstr "Certificates" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsPassword.ts | #: src/pages/user-settings/settings/UserSettingsPassword.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsPassword.ts | ||||||
| msgid "Change password" | msgid "Change password" | ||||||
| msgstr "Change password" | msgstr "Change password" | ||||||
|  |  | ||||||
| @ -610,6 +618,7 @@ msgid "Change status" | |||||||
| msgstr "Change status" | msgstr "Change status" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsPassword.ts | #: src/pages/user-settings/settings/UserSettingsPassword.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsPassword.ts | ||||||
| msgid "Change your password" | msgid "Change your password" | ||||||
| msgstr "Change your password" | msgstr "Change your password" | ||||||
|  |  | ||||||
| @ -788,6 +797,7 @@ msgid "Configuration stage" | |||||||
| msgstr "Configuration stage" | msgstr "Configuration stage" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Configure WebAuthn" | msgid "Configure WebAuthn" | ||||||
| msgstr "Configure WebAuthn" | msgstr "Configure WebAuthn" | ||||||
|  |  | ||||||
| @ -820,6 +830,7 @@ msgid "Configure how the issuer field of the ID Token should be filled." | |||||||
| msgstr "Configure how the issuer field of the ID Token should be filled." | msgstr "Configure how the issuer field of the ID Token should be filled." | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Configure settings relevant to your user profile." | msgid "Configure settings relevant to your user profile." | ||||||
| msgstr "Configure settings relevant to your user profile." | msgstr "Configure settings relevant to your user profile." | ||||||
|  |  | ||||||
| @ -836,11 +847,14 @@ msgid "Configure what data should be used as unique User Identifier. For most ca | |||||||
| msgstr "Configure what data should be used as unique User Identifier. For most cases, the default should be fine." | msgstr "Configure what data should be used as unique User Identifier. For most cases, the default should be fine." | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| msgid "Connect" | msgid "Connect" | ||||||
| msgstr "Connect" | msgstr "Connect" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| #: src/pages/user-settings/settings/SourceSettingsPlex.ts | #: src/pages/user-settings/settings/SourceSettingsPlex.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsPlex.ts | ||||||
| msgid "Connected." | msgid "Connected." | ||||||
| msgstr "Connected." | msgstr "Connected." | ||||||
|  |  | ||||||
| @ -927,6 +941,7 @@ msgid "Copy" | |||||||
| msgstr "Copy" | msgstr "Copy" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Copy Key" | msgid "Copy Key" | ||||||
| msgstr "Copy Key" | msgstr "Copy Key" | ||||||
|  |  | ||||||
| @ -988,11 +1003,15 @@ msgstr "Copy recovery link" | |||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Create" | msgid "Create" | ||||||
| msgstr "Create" | msgstr "Create" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Create App password" | msgid "Create App password" | ||||||
| msgstr "Create App password" | msgstr "Create App password" | ||||||
|  |  | ||||||
| @ -1070,6 +1089,8 @@ msgstr "Create Tenant" | |||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Create Token" | msgid "Create Token" | ||||||
| msgstr "Create Token" | msgstr "Create Token" | ||||||
|  |  | ||||||
| @ -1106,6 +1127,7 @@ msgid "Created by" | |||||||
| msgstr "Created by" | msgstr "Created by" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Created {0}" | msgid "Created {0}" | ||||||
| msgstr "Created {0}" | msgstr "Created {0}" | ||||||
|  |  | ||||||
| @ -1191,6 +1213,8 @@ msgstr "Define how notifications are sent to users, like Email or Webhook." | |||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Delete" | msgid "Delete" | ||||||
| msgstr "Delete" | msgstr "Delete" | ||||||
|  |  | ||||||
| @ -1216,6 +1240,7 @@ msgstr "Delete" | |||||||
| #~ msgstr "Delete Session" | #~ msgstr "Delete Session" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Delete account" | msgid "Delete account" | ||||||
| msgstr "Delete account" | msgstr "Delete account" | ||||||
|  |  | ||||||
| @ -1253,6 +1278,7 @@ msgstr "Deny the user access" | |||||||
| #: src/pages/system-tasks/SystemTaskListPage.ts | #: src/pages/system-tasks/SystemTaskListPage.ts | ||||||
| #: src/pages/tokens/TokenForm.ts | #: src/pages/tokens/TokenForm.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts | #: src/pages/user-settings/tokens/UserTokenForm.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenForm.ts | ||||||
| msgid "Description" | msgid "Description" | ||||||
| msgstr "Description" | msgstr "Description" | ||||||
|  |  | ||||||
| @ -1294,6 +1320,7 @@ msgid "Device classes which can be used to authenticate." | |||||||
| msgstr "Device classes which can be used to authenticate." | msgstr "Device classes which can be used to authenticate." | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Device name" | msgid "Device name" | ||||||
| msgstr "Device name" | msgstr "Device name" | ||||||
|  |  | ||||||
| @ -1312,14 +1339,17 @@ msgstr "Digits" | |||||||
| #~ msgstr "Disable" | #~ msgstr "Disable" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| msgid "Disable Duo authenticator" | msgid "Disable Duo authenticator" | ||||||
| msgstr "Disable Duo authenticator" | msgstr "Disable Duo authenticator" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| msgid "Disable Static Tokens" | msgid "Disable Static Tokens" | ||||||
| msgstr "Disable Static Tokens" | msgstr "Disable Static Tokens" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Disable Time-based OTP" | msgid "Disable Time-based OTP" | ||||||
| msgstr "Disable Time-based OTP" | msgstr "Disable Time-based OTP" | ||||||
|  |  | ||||||
| @ -1329,6 +1359,8 @@ msgstr "Disabled" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| #: src/pages/user-settings/settings/SourceSettingsPlex.ts | #: src/pages/user-settings/settings/SourceSettingsPlex.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsPlex.ts | ||||||
| msgid "Disconnect" | msgid "Disconnect" | ||||||
| msgstr "Disconnect" | msgstr "Disconnect" | ||||||
|  |  | ||||||
| @ -1364,6 +1396,7 @@ msgid "Dummy stage used for testing. Shows a simple continue button and always p | |||||||
| msgstr "Dummy stage used for testing. Shows a simple continue button and always passes." | msgstr "Dummy stage used for testing. Shows a simple continue button and always passes." | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| msgid "Duo" | msgid "Duo" | ||||||
| msgstr "Duo" | msgstr "Duo" | ||||||
|  |  | ||||||
| @ -1423,6 +1456,7 @@ msgid "Edit User" | |||||||
| msgstr "Edit User" | msgstr "Edit User" | ||||||
|  |  | ||||||
| #: src/pages/LibraryPage.ts | #: src/pages/LibraryPage.ts | ||||||
|  | #: src/user/LibraryPage.ts | ||||||
| msgid "Either no applications are defined, or you don't have access to any." | msgid "Either no applications are defined, or you don't have access to any." | ||||||
| msgstr "Either no applications are defined, or you don't have access to any." | msgstr "Either no applications are defined, or you don't have access to any." | ||||||
|  |  | ||||||
| @ -1432,6 +1466,7 @@ msgstr "Either no applications are defined, or you don't have access to any." | |||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
| #: src/pages/users/UserViewPage.ts | #: src/pages/users/UserViewPage.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Email" | msgid "Email" | ||||||
| msgstr "Email" | msgstr "Email" | ||||||
|  |  | ||||||
| @ -1469,6 +1504,7 @@ msgstr "Embedded outpost is not configured correctly." | |||||||
| #~ msgstr "Enable" | #~ msgstr "Enable" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| msgid "Enable Duo authenticator" | msgid "Enable Duo authenticator" | ||||||
| msgstr "Enable Duo authenticator" | msgstr "Enable Duo authenticator" | ||||||
|  |  | ||||||
| @ -1477,10 +1513,12 @@ msgid "Enable StartTLS" | |||||||
| msgstr "Enable StartTLS" | msgstr "Enable StartTLS" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| msgid "Enable Static Tokens" | msgid "Enable Static Tokens" | ||||||
| msgstr "Enable Static Tokens" | msgstr "Enable Static Tokens" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Enable TOTP" | msgid "Enable TOTP" | ||||||
| msgstr "Enable TOTP" | msgstr "Enable TOTP" | ||||||
|  |  | ||||||
| @ -1533,10 +1571,12 @@ msgid "Error when validating assertion on server: {err}" | |||||||
| msgstr "Error when validating assertion on server: {err}" | msgstr "Error when validating assertion on server: {err}" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Error: unsupported source settings: {0}" | msgid "Error: unsupported source settings: {0}" | ||||||
| msgstr "Error: unsupported source settings: {0}" | msgstr "Error: unsupported source settings: {0}" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Error: unsupported stage settings: {0}" | msgid "Error: unsupported stage settings: {0}" | ||||||
| msgstr "Error: unsupported stage settings: {0}" | msgstr "Error: unsupported stage settings: {0}" | ||||||
|  |  | ||||||
| @ -1622,6 +1662,8 @@ msgstr "Expires?" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Expiring" | msgid "Expiring" | ||||||
| msgstr "Expiring" | msgstr "Expiring" | ||||||
|  |  | ||||||
| @ -1884,6 +1926,10 @@ msgstr "Generate" | |||||||
| msgid "Generate Certificate-Key Pair" | msgid "Generate Certificate-Key Pair" | ||||||
| msgstr "Generate Certificate-Key Pair" | msgstr "Generate Certificate-Key Pair" | ||||||
|  |  | ||||||
|  | #: src/interfaces/UserInterface.ts | ||||||
|  | msgid "Go to admin interface" | ||||||
|  | msgstr "Go to admin interface" | ||||||
|  |  | ||||||
| #: src/elements/table/TablePagination.ts | #: src/elements/table/TablePagination.ts | ||||||
| msgid "Go to next page" | msgid "Go to next page" | ||||||
| msgstr "Go to next page" | msgstr "Go to next page" | ||||||
| @ -1892,6 +1938,10 @@ msgstr "Go to next page" | |||||||
| msgid "Go to previous page" | msgid "Go to previous page" | ||||||
| msgstr "Go to previous page" | msgstr "Go to previous page" | ||||||
|  |  | ||||||
|  | #: src/interfaces/AdminInterface.ts | ||||||
|  | msgid "Go to user interface" | ||||||
|  | msgstr "Go to user interface" | ||||||
|  |  | ||||||
| #: src/pages/events/RuleForm.ts | #: src/pages/events/RuleForm.ts | ||||||
| #: src/pages/policies/PolicyBindingForm.ts | #: src/pages/policies/PolicyBindingForm.ts | ||||||
| #: src/pages/policies/PolicyBindingForm.ts | #: src/pages/policies/PolicyBindingForm.ts | ||||||
| @ -2029,6 +2079,8 @@ msgstr "Icon shown in the browser tab." | |||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts | #: src/pages/user-settings/tokens/UserTokenForm.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenForm.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Identifier" | msgid "Identifier" | ||||||
| msgstr "Identifier" | msgstr "Identifier" | ||||||
|  |  | ||||||
| @ -2134,6 +2186,7 @@ msgstr "Integrations" | |||||||
| #: src/pages/tokens/TokenForm.ts | #: src/pages/tokens/TokenForm.ts | ||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Intent" | msgid "Intent" | ||||||
| msgstr "Intent" | msgstr "Intent" | ||||||
|  |  | ||||||
| @ -2274,7 +2327,7 @@ msgstr "Launch URL" | |||||||
| msgid "Let the user identify themselves with their username or Email address." | msgid "Let the user identify themselves with their username or Email address." | ||||||
| msgstr "Let the user identify themselves with their username or Email address." | msgstr "Let the user identify themselves with their username or Email address." | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts | #: src/interfaces/UserInterface.ts | ||||||
| msgid "Library" | msgid "Library" | ||||||
| msgstr "Library" | msgstr "Library" | ||||||
|  |  | ||||||
| @ -2322,6 +2375,7 @@ msgstr "Load servers" | |||||||
| #: src/pages/applications/ApplicationViewPage.ts | #: src/pages/applications/ApplicationViewPage.ts | ||||||
| #: src/pages/applications/ApplicationViewPage.ts | #: src/pages/applications/ApplicationViewPage.ts | ||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| #: src/utils.ts | #: src/utils.ts | ||||||
| msgid "Loading" | msgid "Loading" | ||||||
| msgstr "Loading" | msgstr "Loading" | ||||||
| @ -2541,11 +2595,12 @@ msgstr "Model deleted" | |||||||
| msgid "Model updated" | msgid "Model updated" | ||||||
| msgstr "Model updated" | msgstr "Model updated" | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts | #:  | ||||||
| msgid "Monitor" | #~ msgid "Monitor" | ||||||
| msgstr "Monitor" | #~ msgstr "Monitor" | ||||||
|  |  | ||||||
| #: src/pages/LibraryPage.ts | #: src/pages/LibraryPage.ts | ||||||
|  | #: src/user/LibraryPage.ts | ||||||
| msgid "My Applications" | msgid "My Applications" | ||||||
| msgstr "My Applications" | msgstr "My Applications" | ||||||
|  |  | ||||||
| @ -2627,6 +2682,7 @@ msgstr "My Applications" | |||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserViewPage.ts | #: src/pages/users/UserViewPage.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Name" | msgid "Name" | ||||||
| msgstr "Name" | msgstr "Name" | ||||||
|  |  | ||||||
| @ -2676,10 +2732,12 @@ msgstr "Newly created users are added to this group, if a group is selected." | |||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/users/GroupSelectModal.ts | #: src/pages/users/GroupSelectModal.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "No" | msgid "No" | ||||||
| msgstr "No" | msgstr "No" | ||||||
|  |  | ||||||
| #: src/pages/LibraryPage.ts | #: src/pages/LibraryPage.ts | ||||||
|  | #: src/user/LibraryPage.ts | ||||||
| msgid "No Applications available." | msgid "No Applications available." | ||||||
| msgstr "No Applications available." | msgstr "No Applications available." | ||||||
|  |  | ||||||
| @ -2747,6 +2805,8 @@ msgstr "Not configured action" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| #: src/pages/user-settings/settings/SourceSettingsPlex.ts | #: src/pages/user-settings/settings/SourceSettingsPlex.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsPlex.ts | ||||||
| msgid "Not connected." | msgid "Not connected." | ||||||
| msgstr "Not connected." | msgstr "Not connected." | ||||||
|  |  | ||||||
| @ -3414,6 +3474,7 @@ msgstr "Required." | |||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
| #: src/pages/users/ServiceAccountForm.ts | #: src/pages/users/ServiceAccountForm.ts | ||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only." | msgid "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only." | ||||||
| msgstr "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only." | msgstr "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only." | ||||||
|  |  | ||||||
| @ -3790,6 +3851,8 @@ msgstr "Source linked" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| #: src/pages/user-settings/settings/SourceSettingsPlex.ts | #: src/pages/user-settings/settings/SourceSettingsPlex.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsPlex.ts | ||||||
| msgid "Source {0}" | msgid "Source {0}" | ||||||
| msgstr "Source {0}" | msgstr "Source {0}" | ||||||
|  |  | ||||||
| @ -3900,6 +3963,7 @@ msgid "Static Tokens" | |||||||
| msgstr "Static Tokens" | msgstr "Static Tokens" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| msgid "Static tokens" | msgid "Static tokens" | ||||||
| msgstr "Static tokens" | msgstr "Static tokens" | ||||||
|  |  | ||||||
| @ -3918,12 +3982,18 @@ msgstr "Status" | |||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Status: Disabled" | msgid "Status: Disabled" | ||||||
| msgstr "Status: Disabled" | msgstr "Status: Disabled" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Status: Enabled" | msgid "Status: Enabled" | ||||||
| msgstr "Status: Enabled" | msgstr "Status: Enabled" | ||||||
|  |  | ||||||
| @ -4065,6 +4135,7 @@ msgstr "Successfully created tenant." | |||||||
|  |  | ||||||
| #: src/pages/tokens/TokenForm.ts | #: src/pages/tokens/TokenForm.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts | #: src/pages/user-settings/tokens/UserTokenForm.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenForm.ts | ||||||
| msgid "Successfully created token." | msgid "Successfully created token." | ||||||
| msgstr "Successfully created token." | msgstr "Successfully created token." | ||||||
|  |  | ||||||
| @ -4123,10 +4194,12 @@ msgid "Successfully updated certificate-key pair." | |||||||
| msgstr "Successfully updated certificate-key pair." | msgstr "Successfully updated certificate-key pair." | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Successfully updated details." | msgid "Successfully updated details." | ||||||
| msgstr "Successfully updated details." | msgstr "Successfully updated details." | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Successfully updated device." | msgid "Successfully updated device." | ||||||
| msgstr "Successfully updated device." | msgstr "Successfully updated device." | ||||||
|  |  | ||||||
| @ -4222,6 +4295,7 @@ msgstr "Successfully updated tenant." | |||||||
|  |  | ||||||
| #: src/pages/tokens/TokenForm.ts | #: src/pages/tokens/TokenForm.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts | #: src/pages/user-settings/tokens/UserTokenForm.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenForm.ts | ||||||
| msgid "Successfully updated token." | msgid "Successfully updated token." | ||||||
| msgstr "Successfully updated token." | msgstr "Successfully updated token." | ||||||
|  |  | ||||||
| @ -4465,6 +4539,7 @@ msgid "Time offset when temporary users should be deleted. This only applies if | |||||||
| msgstr "Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. (Format: hours=1;minutes=2;seconds=3)." | msgstr "Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. (Format: hours=1;minutes=2;seconds=3)." | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Time-based One-Time Passwords" | msgid "Time-based One-Time Passwords" | ||||||
| msgstr "Time-based One-Time Passwords" | msgstr "Time-based One-Time Passwords" | ||||||
|  |  | ||||||
| @ -4512,6 +4587,7 @@ msgstr "Token validity" | |||||||
|  |  | ||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Token(s)" | msgid "Token(s)" | ||||||
| msgstr "Token(s)" | msgstr "Token(s)" | ||||||
|  |  | ||||||
| @ -4525,6 +4601,7 @@ msgid "Tokens & App passwords" | |||||||
| msgstr "Tokens & App passwords" | msgstr "Tokens & App passwords" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Tokens and App passwords" | msgid "Tokens and App passwords" | ||||||
| msgstr "Tokens and App passwords" | msgstr "Tokens and App passwords" | ||||||
|  |  | ||||||
| @ -4692,6 +4769,11 @@ msgstr "Up-to-date!" | |||||||
| #: src/pages/users/UserActiveForm.ts | #: src/pages/users/UserActiveForm.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserViewPage.ts | #: src/pages/users/UserViewPage.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Update" | msgid "Update" | ||||||
| msgstr "Update" | msgstr "Update" | ||||||
|  |  | ||||||
| @ -4775,6 +4857,7 @@ msgstr "Update Tenant" | |||||||
|  |  | ||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Update Token" | msgid "Update Token" | ||||||
| msgstr "Update Token" | msgstr "Update Token" | ||||||
|  |  | ||||||
| @ -4789,6 +4872,7 @@ msgid "Update available" | |||||||
| msgstr "Update available" | msgstr "Update available" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Update details" | msgid "Update details" | ||||||
| msgstr "Update details" | msgstr "Update details" | ||||||
|  |  | ||||||
| @ -4867,6 +4951,7 @@ msgstr "Use this tenant for each domain that doesn't have a dedicated tenant." | |||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "User" | msgid "User" | ||||||
| msgstr "User" | msgstr "User" | ||||||
|  |  | ||||||
| @ -4884,6 +4969,7 @@ msgid "User Reputation" | |||||||
| msgstr "User Reputation" | msgstr "User Reputation" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "User Settings" | msgid "User Settings" | ||||||
| msgstr "User Settings" | msgstr "User Settings" | ||||||
|  |  | ||||||
| @ -4900,6 +4986,7 @@ msgid "User database + standard password" | |||||||
| msgstr "User database + standard password" | msgstr "User database + standard password" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "User details" | msgid "User details" | ||||||
| msgstr "User details" | msgstr "User details" | ||||||
|  |  | ||||||
| @ -4943,6 +5030,7 @@ msgstr "User's avatar" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "User's display name." | msgid "User's display name." | ||||||
| msgstr "User's display name." | msgstr "User's display name." | ||||||
|  |  | ||||||
| @ -4971,6 +5059,7 @@ msgstr "Userinfo URL" | |||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserViewPage.ts | #: src/pages/users/UserViewPage.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Username" | msgid "Username" | ||||||
| msgstr "Username" | msgstr "Username" | ||||||
|  |  | ||||||
| @ -5000,6 +5089,10 @@ msgstr "Using flow" | |||||||
| msgid "Using source" | msgid "Using source" | ||||||
| msgstr "Using source" | msgstr "Using source" | ||||||
|  |  | ||||||
|  | #: src/pages/users/ServiceAccountForm.ts | ||||||
|  | msgid "Valid for 360 days, after which the password will automatically rotate. You can copy the password from the Token List." | ||||||
|  | msgstr "Valid for 360 days, after which the password will automatically rotate. You can copy the password from the Token List." | ||||||
|  |  | ||||||
| #: src/pages/providers/oauth2/OAuth2ProviderForm.ts | #: src/pages/providers/oauth2/OAuth2ProviderForm.ts | ||||||
| msgid "Valid redirect URLs after a successful authorization flow. Also specify any origins here for Implicit flows." | msgid "Valid redirect URLs after a successful authorization flow. Also specify any origins here for Implicit flows." | ||||||
| msgstr "Valid redirect URLs after a successful authorization flow. Also specify any origins here for Implicit flows." | msgstr "Valid redirect URLs after a successful authorization flow. Also specify any origins here for Implicit flows." | ||||||
| @ -5085,6 +5178,7 @@ msgid "WebAuthn Authenticators" | |||||||
| msgstr "WebAuthn Authenticators" | msgstr "WebAuthn Authenticators" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "WebAuthn Devices" | msgid "WebAuthn Devices" | ||||||
| msgstr "WebAuthn Devices" | msgstr "WebAuthn Devices" | ||||||
|  |  | ||||||
| @ -5180,6 +5274,7 @@ msgstr "X509 Subject" | |||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/users/GroupSelectModal.ts | #: src/pages/users/GroupSelectModal.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Yes" | msgid "Yes" | ||||||
| msgstr "Yes" | msgstr "Yes" | ||||||
|  |  | ||||||
| @ -5188,6 +5283,7 @@ msgid "You can only select providers that match the type of the outpost." | |||||||
| msgstr "You can only select providers that match the type of the outpost." | msgstr "You can only select providers that match the type of the outpost." | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts | #: src/interfaces/AdminInterface.ts | ||||||
|  | #: src/interfaces/UserInterface.ts | ||||||
| msgid "You're currently impersonating {0}. Click to stop." | msgid "You're currently impersonating {0}. Click to stop." | ||||||
| msgstr "You're currently impersonating {0}. Click to stop." | msgstr "You're currently impersonating {0}. Click to stop." | ||||||
|  |  | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ msgid "8 digits, not compatible with apps like Google Authenticator" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts | #: src/interfaces/AdminInterface.ts | ||||||
|  | #: src/interfaces/UserInterface.ts | ||||||
| msgid "A newer version of the frontend is available." | msgid "A newer version of the frontend is available." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -167,6 +168,10 @@ msgstr "" | |||||||
| msgid "Additional user DN, prepended to the Base DN." | msgid "Additional user DN, prepended to the Base DN." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #:  | ||||||
|  | #~ msgid "Admin" | ||||||
|  | #~ msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/providers/oauth2/OAuth2ProviderForm.ts | #: src/pages/providers/oauth2/OAuth2ProviderForm.ts | ||||||
| #: src/pages/providers/proxy/ProxyProviderForm.ts | #: src/pages/providers/proxy/ProxyProviderForm.ts | ||||||
| #: src/pages/providers/saml/SAMLProviderForm.ts | #: src/pages/providers/saml/SAMLProviderForm.ts | ||||||
| @ -282,6 +287,7 @@ msgstr "" | |||||||
| #: src/pages/LibraryPage.ts | #: src/pages/LibraryPage.ts | ||||||
| #: src/pages/applications/ApplicationListPage.ts | #: src/pages/applications/ApplicationListPage.ts | ||||||
| #: src/pages/outposts/OutpostForm.ts | #: src/pages/outposts/OutpostForm.ts | ||||||
|  | #: src/user/LibraryPage.ts | ||||||
| msgid "Applications" | msgid "Applications" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -377,6 +383,7 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts | #: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Authenticator" | msgid "Authenticator" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -598,6 +605,7 @@ msgid "Certificates" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsPassword.ts | #: src/pages/user-settings/settings/UserSettingsPassword.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsPassword.ts | ||||||
| msgid "Change password" | msgid "Change password" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -606,6 +614,7 @@ msgid "Change status" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsPassword.ts | #: src/pages/user-settings/settings/UserSettingsPassword.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsPassword.ts | ||||||
| msgid "Change your password" | msgid "Change your password" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -782,6 +791,7 @@ msgid "Configuration stage" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Configure WebAuthn" | msgid "Configure WebAuthn" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -814,6 +824,7 @@ msgid "Configure how the issuer field of the ID Token should be filled." | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Configure settings relevant to your user profile." | msgid "Configure settings relevant to your user profile." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -830,11 +841,14 @@ msgid "Configure what data should be used as unique User Identifier. For most ca | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| msgid "Connect" | msgid "Connect" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| #: src/pages/user-settings/settings/SourceSettingsPlex.ts | #: src/pages/user-settings/settings/SourceSettingsPlex.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsPlex.ts | ||||||
| msgid "Connected." | msgid "Connected." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -921,6 +935,7 @@ msgid "Copy" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Copy Key" | msgid "Copy Key" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -982,11 +997,15 @@ msgstr "" | |||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Create" | msgid "Create" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Create App password" | msgid "Create App password" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1064,6 +1083,8 @@ msgstr "" | |||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Create Token" | msgid "Create Token" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1100,6 +1121,7 @@ msgid "Created by" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Created {0}" | msgid "Created {0}" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1185,6 +1207,8 @@ msgstr "" | |||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Delete" | msgid "Delete" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1210,6 +1234,7 @@ msgstr "" | |||||||
| #~ msgstr "" | #~ msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Delete account" | msgid "Delete account" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1245,6 +1270,7 @@ msgstr "" | |||||||
| #: src/pages/system-tasks/SystemTaskListPage.ts | #: src/pages/system-tasks/SystemTaskListPage.ts | ||||||
| #: src/pages/tokens/TokenForm.ts | #: src/pages/tokens/TokenForm.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts | #: src/pages/user-settings/tokens/UserTokenForm.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenForm.ts | ||||||
| msgid "Description" | msgid "Description" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1286,6 +1312,7 @@ msgid "Device classes which can be used to authenticate." | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Device name" | msgid "Device name" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1304,14 +1331,17 @@ msgstr "" | |||||||
| #~ msgstr "" | #~ msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| msgid "Disable Duo authenticator" | msgid "Disable Duo authenticator" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| msgid "Disable Static Tokens" | msgid "Disable Static Tokens" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Disable Time-based OTP" | msgid "Disable Time-based OTP" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1321,6 +1351,8 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| #: src/pages/user-settings/settings/SourceSettingsPlex.ts | #: src/pages/user-settings/settings/SourceSettingsPlex.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsPlex.ts | ||||||
| msgid "Disconnect" | msgid "Disconnect" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1356,6 +1388,7 @@ msgid "Dummy stage used for testing. Shows a simple continue button and always p | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| msgid "Duo" | msgid "Duo" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1415,6 +1448,7 @@ msgid "Edit User" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/LibraryPage.ts | #: src/pages/LibraryPage.ts | ||||||
|  | #: src/user/LibraryPage.ts | ||||||
| msgid "Either no applications are defined, or you don't have access to any." | msgid "Either no applications are defined, or you don't have access to any." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1424,6 +1458,7 @@ msgstr "" | |||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
| #: src/pages/users/UserViewPage.ts | #: src/pages/users/UserViewPage.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Email" | msgid "Email" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1461,6 +1496,7 @@ msgstr "" | |||||||
| #~ msgstr "" | #~ msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| msgid "Enable Duo authenticator" | msgid "Enable Duo authenticator" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1469,10 +1505,12 @@ msgid "Enable StartTLS" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| msgid "Enable Static Tokens" | msgid "Enable Static Tokens" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Enable TOTP" | msgid "Enable TOTP" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1525,10 +1563,12 @@ msgid "Error when validating assertion on server: {err}" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Error: unsupported source settings: {0}" | msgid "Error: unsupported source settings: {0}" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Error: unsupported stage settings: {0}" | msgid "Error: unsupported stage settings: {0}" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1614,6 +1654,8 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Expiring" | msgid "Expiring" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1876,6 +1918,10 @@ msgstr "" | |||||||
| msgid "Generate Certificate-Key Pair" | msgid "Generate Certificate-Key Pair" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #: src/interfaces/UserInterface.ts | ||||||
|  | msgid "Go to admin interface" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #: src/elements/table/TablePagination.ts | #: src/elements/table/TablePagination.ts | ||||||
| msgid "Go to next page" | msgid "Go to next page" | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -1884,6 +1930,10 @@ msgstr "" | |||||||
| msgid "Go to previous page" | msgid "Go to previous page" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #: src/interfaces/AdminInterface.ts | ||||||
|  | msgid "Go to user interface" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/events/RuleForm.ts | #: src/pages/events/RuleForm.ts | ||||||
| #: src/pages/policies/PolicyBindingForm.ts | #: src/pages/policies/PolicyBindingForm.ts | ||||||
| #: src/pages/policies/PolicyBindingForm.ts | #: src/pages/policies/PolicyBindingForm.ts | ||||||
| @ -2021,6 +2071,8 @@ msgstr "" | |||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts | #: src/pages/user-settings/tokens/UserTokenForm.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenForm.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Identifier" | msgid "Identifier" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -2126,6 +2178,7 @@ msgstr "" | |||||||
| #: src/pages/tokens/TokenForm.ts | #: src/pages/tokens/TokenForm.ts | ||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Intent" | msgid "Intent" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -2266,7 +2319,7 @@ msgstr "" | |||||||
| msgid "Let the user identify themselves with their username or Email address." | msgid "Let the user identify themselves with their username or Email address." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts | #: src/interfaces/UserInterface.ts | ||||||
| msgid "Library" | msgid "Library" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -2314,6 +2367,7 @@ msgstr "" | |||||||
| #: src/pages/applications/ApplicationViewPage.ts | #: src/pages/applications/ApplicationViewPage.ts | ||||||
| #: src/pages/applications/ApplicationViewPage.ts | #: src/pages/applications/ApplicationViewPage.ts | ||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| #: src/utils.ts | #: src/utils.ts | ||||||
| msgid "Loading" | msgid "Loading" | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -2533,11 +2587,12 @@ msgstr "" | |||||||
| msgid "Model updated" | msgid "Model updated" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts | #:  | ||||||
| msgid "Monitor" | #~ msgid "Monitor" | ||||||
| msgstr "" | #~ msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/LibraryPage.ts | #: src/pages/LibraryPage.ts | ||||||
|  | #: src/user/LibraryPage.ts | ||||||
| msgid "My Applications" | msgid "My Applications" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -2619,6 +2674,7 @@ msgstr "" | |||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserViewPage.ts | #: src/pages/users/UserViewPage.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Name" | msgid "Name" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -2668,10 +2724,12 @@ msgstr "" | |||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/users/GroupSelectModal.ts | #: src/pages/users/GroupSelectModal.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "No" | msgid "No" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/LibraryPage.ts | #: src/pages/LibraryPage.ts | ||||||
|  | #: src/user/LibraryPage.ts | ||||||
| msgid "No Applications available." | msgid "No Applications available." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -2739,6 +2797,8 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| #: src/pages/user-settings/settings/SourceSettingsPlex.ts | #: src/pages/user-settings/settings/SourceSettingsPlex.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsPlex.ts | ||||||
| msgid "Not connected." | msgid "Not connected." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -3406,6 +3466,7 @@ msgstr "" | |||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
| #: src/pages/users/ServiceAccountForm.ts | #: src/pages/users/ServiceAccountForm.ts | ||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only." | msgid "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -3782,6 +3843,8 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | #: src/pages/user-settings/settings/SourceSettingsOAuth.ts | ||||||
| #: src/pages/user-settings/settings/SourceSettingsPlex.ts | #: src/pages/user-settings/settings/SourceSettingsPlex.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsOAuth.ts | ||||||
|  | #: src/user/user-settings/settings/SourceSettingsPlex.ts | ||||||
| msgid "Source {0}" | msgid "Source {0}" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -3892,6 +3955,7 @@ msgid "Static Tokens" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| msgid "Static tokens" | msgid "Static tokens" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -3910,12 +3974,18 @@ msgstr "" | |||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Status: Disabled" | msgid "Status: Disabled" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorDuo.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorStatic.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Status: Enabled" | msgid "Status: Enabled" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4057,6 +4127,7 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/tokens/TokenForm.ts | #: src/pages/tokens/TokenForm.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts | #: src/pages/user-settings/tokens/UserTokenForm.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenForm.ts | ||||||
| msgid "Successfully created token." | msgid "Successfully created token." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4115,10 +4186,12 @@ msgid "Successfully updated certificate-key pair." | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Successfully updated details." | msgid "Successfully updated details." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "Successfully updated device." | msgid "Successfully updated device." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4214,6 +4287,7 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/tokens/TokenForm.ts | #: src/pages/tokens/TokenForm.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts | #: src/pages/user-settings/tokens/UserTokenForm.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenForm.ts | ||||||
| msgid "Successfully updated token." | msgid "Successfully updated token." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4450,6 +4524,7 @@ msgid "Time offset when temporary users should be deleted. This only applies if | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorTOTP.ts | ||||||
| msgid "Time-based One-Time Passwords" | msgid "Time-based One-Time Passwords" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4497,6 +4572,7 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Token(s)" | msgid "Token(s)" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4510,6 +4586,7 @@ msgid "Tokens & App passwords" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Tokens and App passwords" | msgid "Tokens and App passwords" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4677,6 +4754,11 @@ msgstr "" | |||||||
| #: src/pages/users/UserActiveForm.ts | #: src/pages/users/UserActiveForm.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserViewPage.ts | #: src/pages/users/UserViewPage.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Update" | msgid "Update" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4760,6 +4842,7 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Update Token" | msgid "Update Token" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4774,6 +4857,7 @@ msgid "Update available" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "Update details" | msgid "Update details" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4852,6 +4936,7 @@ msgstr "" | |||||||
| #: src/pages/tokens/TokenListPage.ts | #: src/pages/tokens/TokenListPage.ts | ||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "User" | msgid "User" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4869,6 +4954,7 @@ msgid "User Reputation" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "User Settings" | msgid "User Settings" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4885,6 +4971,7 @@ msgid "User database + standard password" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSettingsPage.ts | #: src/pages/user-settings/UserSettingsPage.ts | ||||||
|  | #: src/user/user-settings/UserSettingsPage.ts | ||||||
| msgid "User details" | msgid "User details" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4928,6 +5015,7 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/user-settings/UserSelfForm.ts | #: src/pages/user-settings/UserSelfForm.ts | ||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "User's display name." | msgid "User's display name." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4956,6 +5044,7 @@ msgstr "" | |||||||
| #: src/pages/users/UserForm.ts | #: src/pages/users/UserForm.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
| #: src/pages/users/UserViewPage.ts | #: src/pages/users/UserViewPage.ts | ||||||
|  | #: src/user/user-settings/UserSelfForm.ts | ||||||
| msgid "Username" | msgid "Username" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4985,6 +5074,10 @@ msgstr "" | |||||||
| msgid "Using source" | msgid "Using source" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #: src/pages/users/ServiceAccountForm.ts | ||||||
|  | msgid "Valid for 360 days, after which the password will automatically rotate. You can copy the password from the Token List." | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/providers/oauth2/OAuth2ProviderForm.ts | #: src/pages/providers/oauth2/OAuth2ProviderForm.ts | ||||||
| msgid "Valid redirect URLs after a successful authorization flow. Also specify any origins here for Implicit flows." | msgid "Valid redirect URLs after a successful authorization flow. Also specify any origins here for Implicit flows." | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -5070,6 +5163,7 @@ msgid "WebAuthn Authenticators" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | #: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
|  | #: src/user/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts | ||||||
| msgid "WebAuthn Devices" | msgid "WebAuthn Devices" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -5163,6 +5257,7 @@ msgstr "" | |||||||
| #: src/pages/user-settings/tokens/UserTokenList.ts | #: src/pages/user-settings/tokens/UserTokenList.ts | ||||||
| #: src/pages/users/GroupSelectModal.ts | #: src/pages/users/GroupSelectModal.ts | ||||||
| #: src/pages/users/UserListPage.ts | #: src/pages/users/UserListPage.ts | ||||||
|  | #: src/user/user-settings/tokens/UserTokenList.ts | ||||||
| msgid "Yes" | msgid "Yes" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -5171,6 +5266,7 @@ msgid "You can only select providers that match the type of the outpost." | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts | #: src/interfaces/AdminInterface.ts | ||||||
|  | #: src/interfaces/UserInterface.ts | ||||||
| msgid "You're currently impersonating {0}. Click to stop." | msgid "You're currently impersonating {0}. Click to stop." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ import "./pages/events/TransportListPage"; | |||||||
| import "./pages/flows/FlowListPage"; | import "./pages/flows/FlowListPage"; | ||||||
| import "./pages/flows/FlowViewPage"; | import "./pages/flows/FlowViewPage"; | ||||||
| import "./pages/groups/GroupListPage"; | import "./pages/groups/GroupListPage"; | ||||||
| import "./pages/LibraryPage"; | import "./user/LibraryPage"; | ||||||
| import "./pages/outposts/OutpostListPage"; | import "./pages/outposts/OutpostListPage"; | ||||||
| import "./pages/outposts/ServiceConnectionListPage"; | import "./pages/outposts/ServiceConnectionListPage"; | ||||||
| import "./pages/policies/PolicyListPage"; | import "./pages/policies/PolicyListPage"; | ||||||
| @ -35,8 +35,8 @@ import "./pages/users/UserViewPage"; | |||||||
| 
 | 
 | ||||||
| export const ROUTES: Route[] = [ | export const ROUTES: Route[] = [ | ||||||
|     // Prevent infinite Shell loops
 |     // Prevent infinite Shell loops
 | ||||||
|     new Route(new RegExp("^/$")).redirect("/library"), |     new Route(new RegExp("^/$")).redirect("/administration/overview"), | ||||||
|     new Route(new RegExp("^#.*")).redirect("/library"), |     new Route(new RegExp("^#.*")).redirect("/administration/overview"), | ||||||
|     new Route(new RegExp("^/library$"), html`<ak-library></ak-library>`), |     new Route(new RegExp("^/library$"), html`<ak-library></ak-library>`), | ||||||
|     new Route( |     new Route( | ||||||
|         new RegExp("^/administration/overview$"), |         new RegExp("^/administration/overview$"), | ||||||
							
								
								
									
										13
									
								
								web/src/routesUser.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								web/src/routesUser.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | import { html } from "lit-html"; | ||||||
|  | import { Route } from "./elements/router/Route"; | ||||||
|  |  | ||||||
|  | import "./user/LibraryPage"; | ||||||
|  | import "./user/user-settings/UserSettingsPage"; | ||||||
|  |  | ||||||
|  | export const ROUTES: Route[] = [ | ||||||
|  |     // Prevent infinite Shell loops | ||||||
|  |     new Route(new RegExp("^/$")).redirect("/library"), | ||||||
|  |     new Route(new RegExp("^#.*")).redirect("/library"), | ||||||
|  |     new Route(new RegExp("^/library$"), html`<ak-library></ak-library>`), | ||||||
|  |     new Route(new RegExp("^/user$"), html`<ak-user-settings></ak-user-settings>`), | ||||||
|  | ]; | ||||||
							
								
								
									
										170
									
								
								web/src/user/LibraryPage.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								web/src/user/LibraryPage.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,170 @@ | |||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { | ||||||
|  |     css, | ||||||
|  |     CSSResult, | ||||||
|  |     customElement, | ||||||
|  |     html, | ||||||
|  |     LitElement, | ||||||
|  |     property, | ||||||
|  |     TemplateResult, | ||||||
|  | } from "lit-element"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { Application, CoreApi } from "@goauthentik/api"; | ||||||
|  | import { AKResponse } from "../api/Client"; | ||||||
|  | import { DEFAULT_CONFIG } from "../api/Config"; | ||||||
|  | import { me } from "../api/Users"; | ||||||
|  | import { loading, truncate } from "../utils"; | ||||||
|  | import "../elements/PageHeader"; | ||||||
|  | import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||||
|  | import PFCard from "@patternfly/patternfly/components/Card/card.css"; | ||||||
|  | import PFTitle from "@patternfly/patternfly/components/Title/title.css"; | ||||||
|  | import PFEmptyState from "@patternfly/patternfly/components/EmptyState/empty-state.css"; | ||||||
|  | import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||||
|  | import PFContent from "@patternfly/patternfly/components/Content/content.css"; | ||||||
|  | import AKGlobal from "../authentik.css"; | ||||||
|  | import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css"; | ||||||
|  | import PFGallery from "@patternfly/patternfly/layouts/Gallery/gallery.css"; | ||||||
|  | import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||||||
|  |  | ||||||
|  | @customElement("ak-library-app") | ||||||
|  | export class LibraryApplication extends LitElement { | ||||||
|  |     @property({ attribute: false }) | ||||||
|  |     application?: Application; | ||||||
|  |  | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return [ | ||||||
|  |             PFBase, | ||||||
|  |             PFCard, | ||||||
|  |             PFButton, | ||||||
|  |             PFAvatar, | ||||||
|  |             AKGlobal, | ||||||
|  |             css` | ||||||
|  |                 .pf-c-card { | ||||||
|  |                     height: 100%; | ||||||
|  |                 } | ||||||
|  |                 i.pf-icon { | ||||||
|  |                     height: 36px; | ||||||
|  |                     display: flex; | ||||||
|  |                     flex-direction: column; | ||||||
|  |                     justify-content: center; | ||||||
|  |                 } | ||||||
|  |                 .pf-c-avatar { | ||||||
|  |                     --pf-c-avatar--BorderRadius: 0; | ||||||
|  |                 } | ||||||
|  |                 .pf-c-card__header { | ||||||
|  |                     min-height: 60px; | ||||||
|  |                     justify-content: space-between; | ||||||
|  |                 } | ||||||
|  |                 .pf-c-card__header a { | ||||||
|  |                     display: flex; | ||||||
|  |                     flex-direction: column; | ||||||
|  |                     justify-content: center; | ||||||
|  |                     margin-right: 0.25em; | ||||||
|  |                 } | ||||||
|  |             `, | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         if (!this.application) { | ||||||
|  |             return html`<ak-spinner></ak-spinner>`; | ||||||
|  |         } | ||||||
|  |         return html` <div class="pf-c-card pf-m-hoverable pf-m-compact"> | ||||||
|  |             <div class="pf-c-card__header"> | ||||||
|  |                 ${this.application.metaIcon | ||||||
|  |                     ? html`<a href="${ifDefined(this.application.launchUrl ?? "")}" | ||||||
|  |                           ><img | ||||||
|  |                               class="app-icon pf-c-avatar" | ||||||
|  |                               src="${ifDefined(this.application.metaIcon)}" | ||||||
|  |                               alt="Application Icon" | ||||||
|  |                       /></a>` | ||||||
|  |                     : html`<i class="fas fas fa-share-square"></i>`} | ||||||
|  |                 ${until( | ||||||
|  |                     me().then((u) => { | ||||||
|  |                         if (!u.user.isSuperuser) return html``; | ||||||
|  |                         return html` | ||||||
|  |                             <a | ||||||
|  |                                 class="pf-c-button pf-m-control pf-m-small" | ||||||
|  |                                 href="#/core/applications/${this.application?.slug}" | ||||||
|  |                             > | ||||||
|  |                                 <i class="fas fa-pencil-alt"></i> | ||||||
|  |                             </a> | ||||||
|  |                         `; | ||||||
|  |                     }), | ||||||
|  |                 )} | ||||||
|  |             </div> | ||||||
|  |             <div class="pf-c-card__title"> | ||||||
|  |                 <p id="card-1-check-label"> | ||||||
|  |                     <a href="${ifDefined(this.application.launchUrl ?? "")}" | ||||||
|  |                         >${this.application.name}</a | ||||||
|  |                     > | ||||||
|  |                 </p> | ||||||
|  |                 <div class="pf-c-content"> | ||||||
|  |                     <small>${this.application.metaPublisher}</small> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |             <div class="pf-c-card__body">${truncate(this.application.metaDescription, 35)}</div> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @customElement("ak-library") | ||||||
|  | export class LibraryPage extends LitElement { | ||||||
|  |     @property({ attribute: false }) | ||||||
|  |     apps?: AKResponse<Application>; | ||||||
|  |  | ||||||
|  |     pageTitle(): string { | ||||||
|  |         return t`My Applications`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return [PFBase, PFEmptyState, PFTitle, PFPage, PFContent, PFGallery, AKGlobal].concat(css` | ||||||
|  |             :host, | ||||||
|  |             main { | ||||||
|  |                 height: 100%; | ||||||
|  |             } | ||||||
|  |         `); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     firstUpdated(): void { | ||||||
|  |         new CoreApi(DEFAULT_CONFIG).coreApplicationsList({}).then((apps) => { | ||||||
|  |             this.apps = apps; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderEmptyState(): TemplateResult { | ||||||
|  |         return html` <div class="pf-c-empty-state pf-m-full-height"> | ||||||
|  |             <div class="pf-c-empty-state__content"> | ||||||
|  |                 <i class="fas fa-cubes pf-c-empty-state__icon" aria-hidden="true"></i> | ||||||
|  |                 <h1 class="pf-c-title pf-m-lg">${t`No Applications available.`}</h1> | ||||||
|  |                 <div class="pf-c-empty-state__body"> | ||||||
|  |                     ${t`Either no applications are defined, or you don't have access to any.`} | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderApps(): TemplateResult { | ||||||
|  |         return html`<div class="pf-l-gallery pf-m-gutter"> | ||||||
|  |             ${this.apps?.results.map( | ||||||
|  |                 (app) => html`<ak-library-app .application=${app}></ak-library-app>`, | ||||||
|  |             )} | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         return html`<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content"> | ||||||
|  |             <ak-page-header icon="pf-icon pf-icon-applications" header=${t`Applications`}> | ||||||
|  |             </ak-page-header> | ||||||
|  |             <section class="pf-c-page__main-section"> | ||||||
|  |                 ${loading( | ||||||
|  |                     this.apps, | ||||||
|  |                     html`${(this.apps?.results.length || 0) > 0 | ||||||
|  |                         ? this.renderApps() | ||||||
|  |                         : this.renderEmptyState()}`, | ||||||
|  |                 )} | ||||||
|  |             </section> | ||||||
|  |         </main>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								web/src/user/user-settings/UserSelfForm.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								web/src/user/user-settings/UserSelfForm.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | |||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { customElement, html, TemplateResult } from "lit-element"; | ||||||
|  | import { CoreApi, UserSelf } from "@goauthentik/api"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | import { DEFAULT_CONFIG, tenant } from "../../api/Config"; | ||||||
|  | import "../../elements/forms/FormElement"; | ||||||
|  | import "../../elements/EmptyState"; | ||||||
|  | import "../../elements/forms/Form"; | ||||||
|  | import "../../elements/forms/HorizontalFormElement"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { ModelForm } from "../../elements/forms/ModelForm"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-self-form") | ||||||
|  | export class UserSelfForm extends ModelForm<UserSelf, number> { | ||||||
|  |     viewportCheck = false; | ||||||
|  |  | ||||||
|  |     // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||||||
|  |     loadInstance(pk: number): Promise<UserSelf> { | ||||||
|  |         return new CoreApi(DEFAULT_CONFIG).coreUsersMeRetrieve().then((su) => { | ||||||
|  |             return su.user; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getSuccessMessage(): string { | ||||||
|  |         return t`Successfully updated details.`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send = (data: UserSelf): Promise<UserSelf> => { | ||||||
|  |         return new CoreApi(DEFAULT_CONFIG) | ||||||
|  |             .coreUsersUpdateSelfUpdate({ | ||||||
|  |                 userSelfRequest: data, | ||||||
|  |             }) | ||||||
|  |             .then((su) => { | ||||||
|  |                 return su.user; | ||||||
|  |             }); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     renderForm(): TemplateResult { | ||||||
|  |         if (!this.instance) { | ||||||
|  |             return html`<ak-empty-state ?loading="${true}" header=${t`Loading`}> </ak-empty-state>`; | ||||||
|  |         } | ||||||
|  |         return html`<form class="pf-c-form pf-m-horizontal"> | ||||||
|  |             <ak-form-element-horizontal label=${t`Username`} ?required=${true} name="username"> | ||||||
|  |                 <input | ||||||
|  |                     type="text" | ||||||
|  |                     value="${ifDefined(this.instance?.username)}" | ||||||
|  |                     class="pf-c-form-control" | ||||||
|  |                     required | ||||||
|  |                 /> | ||||||
|  |                 <p class="pf-c-form__helper-text"> | ||||||
|  |                     ${t`Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.`} | ||||||
|  |                 </p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name"> | ||||||
|  |                 <input | ||||||
|  |                     type="text" | ||||||
|  |                     value="${ifDefined(this.instance?.name)}" | ||||||
|  |                     class="pf-c-form-control" | ||||||
|  |                     required | ||||||
|  |                 /> | ||||||
|  |                 <p class="pf-c-form__helper-text">${t`User's display name.`}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal label=${t`Email`} name="email"> | ||||||
|  |                 <input | ||||||
|  |                     type="email" | ||||||
|  |                     value="${ifDefined(this.instance?.email)}" | ||||||
|  |                     class="pf-c-form-control" | ||||||
|  |                 /> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <div class="pf-c-form__group pf-m-action"> | ||||||
|  |                 <div class="pf-c-form__horizontal-group"> | ||||||
|  |                     <div class="pf-c-form__actions"> | ||||||
|  |                         <button | ||||||
|  |                             @click=${(ev: Event) => { | ||||||
|  |                                 return this.submit(ev); | ||||||
|  |                             }} | ||||||
|  |                             class="pf-c-button pf-m-primary" | ||||||
|  |                         > | ||||||
|  |                             ${t`Update`} | ||||||
|  |                         </button> | ||||||
|  |                         ${until( | ||||||
|  |                             tenant().then((tenant) => { | ||||||
|  |                                 if (tenant.flowUnenrollment) { | ||||||
|  |                                     return html`<a | ||||||
|  |                                         class="pf-c-button pf-m-danger" | ||||||
|  |                                         href="/if/flow/${tenant.flowUnenrollment}" | ||||||
|  |                                     > | ||||||
|  |                                         ${t`Delete account`} | ||||||
|  |                                     </a>`; | ||||||
|  |                                 } | ||||||
|  |                                 return html``; | ||||||
|  |                             }), | ||||||
|  |                         )} | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </form>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										186
									
								
								web/src/user/user-settings/UserSettingsPage.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								web/src/user/user-settings/UserSettingsPage.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,186 @@ | |||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||||
|  |  | ||||||
|  | import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||||
|  | import PFContent from "@patternfly/patternfly/components/Content/content.css"; | ||||||
|  | import PFGallery from "@patternfly/patternfly/layouts/Gallery/gallery.css"; | ||||||
|  | import PFCard from "@patternfly/patternfly/components/Card/card.css"; | ||||||
|  | import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; | ||||||
|  | import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css"; | ||||||
|  | import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css"; | ||||||
|  | import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css"; | ||||||
|  | import AKGlobal from "../../authentik.css"; | ||||||
|  | import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||||
|  | import PFForm from "@patternfly/patternfly/components/Form/form.css"; | ||||||
|  | import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | ||||||
|  | import { SourcesApi, StagesApi, UserSetting } from "@goauthentik/api"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../api/Config"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | import "../../elements/Tabs"; | ||||||
|  | import "../../elements/PageHeader"; | ||||||
|  | import "./tokens/UserTokenList"; | ||||||
|  | import "./UserSelfForm"; | ||||||
|  | import "./settings/UserSettingsAuthenticatorDuo"; | ||||||
|  | import "./settings/UserSettingsAuthenticatorStatic"; | ||||||
|  | import "./settings/UserSettingsAuthenticatorTOTP"; | ||||||
|  | import "./settings/UserSettingsAuthenticatorWebAuthn"; | ||||||
|  | import "./settings/UserSettingsPassword"; | ||||||
|  | import "./settings/SourceSettingsOAuth"; | ||||||
|  | import "./settings/SourceSettingsPlex"; | ||||||
|  | import { EVENT_REFRESH } from "../../constants"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-settings") | ||||||
|  | export class UserSettingsPage extends LitElement { | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return [ | ||||||
|  |             PFBase, | ||||||
|  |             PFPage, | ||||||
|  |             PFFlex, | ||||||
|  |             PFDisplay, | ||||||
|  |             PFGallery, | ||||||
|  |             PFContent, | ||||||
|  |             PFCard, | ||||||
|  |             PFDescriptionList, | ||||||
|  |             PFSizing, | ||||||
|  |             PFForm, | ||||||
|  |             PFFormControl, | ||||||
|  |             AKGlobal, | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @property({ attribute: false }) | ||||||
|  |     userSettings?: Promise<UserSetting[]>; | ||||||
|  |  | ||||||
|  |     @property({ attribute: false }) | ||||||
|  |     sourceSettings?: Promise<UserSetting[]>; | ||||||
|  |  | ||||||
|  |     constructor() { | ||||||
|  |         super(); | ||||||
|  |         this.addEventListener(EVENT_REFRESH, () => { | ||||||
|  |             this.firstUpdated(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     firstUpdated(): void { | ||||||
|  |         this.userSettings = new StagesApi(DEFAULT_CONFIG).stagesAllUserSettingsList(); | ||||||
|  |         this.sourceSettings = new SourcesApi(DEFAULT_CONFIG).sourcesAllUserSettingsList(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderStageSettings(stage: UserSetting): TemplateResult { | ||||||
|  |         switch (stage.component) { | ||||||
|  |             case "ak-user-settings-authenticator-webauthn": | ||||||
|  |                 return html`<ak-user-settings-authenticator-webauthn | ||||||
|  |                     objectId=${stage.objectUid} | ||||||
|  |                     .configureUrl=${stage.configureUrl} | ||||||
|  |                 > | ||||||
|  |                 </ak-user-settings-authenticator-webauthn>`; | ||||||
|  |             case "ak-user-settings-password": | ||||||
|  |                 return html`<ak-user-settings-password | ||||||
|  |                     objectId=${stage.objectUid} | ||||||
|  |                     .configureUrl=${stage.configureUrl} | ||||||
|  |                 > | ||||||
|  |                 </ak-user-settings-password>`; | ||||||
|  |             case "ak-user-settings-authenticator-totp": | ||||||
|  |                 return html`<ak-user-settings-authenticator-totp | ||||||
|  |                     objectId=${stage.objectUid} | ||||||
|  |                     .configureUrl=${stage.configureUrl} | ||||||
|  |                 > | ||||||
|  |                 </ak-user-settings-authenticator-totp>`; | ||||||
|  |             case "ak-user-settings-authenticator-static": | ||||||
|  |                 return html`<ak-user-settings-authenticator-static | ||||||
|  |                     objectId=${stage.objectUid} | ||||||
|  |                     .configureUrl=${stage.configureUrl} | ||||||
|  |                 > | ||||||
|  |                 </ak-user-settings-authenticator-static>`; | ||||||
|  |             case "ak-user-settings-authenticator-duo": | ||||||
|  |                 return html`<ak-user-settings-authenticator-duo | ||||||
|  |                     objectId=${stage.objectUid} | ||||||
|  |                     .configureUrl=${stage.configureUrl} | ||||||
|  |                 > | ||||||
|  |                 </ak-user-settings-authenticator-duo>`; | ||||||
|  |             default: | ||||||
|  |                 return html`<p>${t`Error: unsupported stage settings: ${stage.component}`}</p>`; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderSourceSettings(source: UserSetting): TemplateResult { | ||||||
|  |         switch (source.component) { | ||||||
|  |             case "ak-user-settings-source-oauth": | ||||||
|  |                 return html`<ak-user-settings-source-oauth | ||||||
|  |                     objectId=${source.objectUid} | ||||||
|  |                     title=${source.title} | ||||||
|  |                     .configureUrl=${source.configureUrl} | ||||||
|  |                 > | ||||||
|  |                 </ak-user-settings-source-oauth>`; | ||||||
|  |             case "ak-user-settings-source-plex": | ||||||
|  |                 return html`<ak-user-settings-source-plex | ||||||
|  |                     objectId=${source.objectUid} | ||||||
|  |                     title=${source.title} | ||||||
|  |                 > | ||||||
|  |                 </ak-user-settings-source-plex>`; | ||||||
|  |             default: | ||||||
|  |                 return html`<p>${t`Error: unsupported source settings: ${source.component}`}</p>`; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-page"> | ||||||
|  |             <main role="main" class="pf-c-page__main" tabindex="-1"> | ||||||
|  |                 <ak-page-header | ||||||
|  |                     icon="pf-icon pf-icon-user" | ||||||
|  |                     header=${t`User Settings`} | ||||||
|  |                     description=${t`Configure settings relevant to your user profile.`} | ||||||
|  |                 > | ||||||
|  |                 </ak-page-header> | ||||||
|  |                 <ak-tabs ?vertical="${true}" style="height: 100%;"> | ||||||
|  |                     <section | ||||||
|  |                         slot="page-details" | ||||||
|  |                         data-tab-title="${t`User details`}" | ||||||
|  |                         class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||||
|  |                     > | ||||||
|  |                         <div class="pf-c-card"> | ||||||
|  |                             <div class="pf-c-card__title">${t`Update details`}</div> | ||||||
|  |                             <div class="pf-c-card__body"> | ||||||
|  |                                 <ak-user-self-form .instancePk=${1}></ak-user-self-form> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                     </section> | ||||||
|  |                     <section | ||||||
|  |                         slot="page-tokens" | ||||||
|  |                         data-tab-title="${t`Tokens and App passwords`}" | ||||||
|  |                         class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||||
|  |                     > | ||||||
|  |                         <ak-user-token-list></ak-user-token-list> | ||||||
|  |                     </section> | ||||||
|  |                     ${until( | ||||||
|  |                         this.userSettings?.then((stages) => { | ||||||
|  |                             return stages.map((stage) => { | ||||||
|  |                                 return html`<section | ||||||
|  |                                     slot="page-${stage.objectUid}" | ||||||
|  |                                     data-tab-title="${ifDefined(stage.title)}" | ||||||
|  |                                     class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||||
|  |                                 > | ||||||
|  |                                     ${this.renderStageSettings(stage)} | ||||||
|  |                                 </section>`; | ||||||
|  |                             }); | ||||||
|  |                         }), | ||||||
|  |                     )} | ||||||
|  |                     ${until( | ||||||
|  |                         this.sourceSettings?.then((source) => { | ||||||
|  |                             return source.map((stage) => { | ||||||
|  |                                 return html`<section | ||||||
|  |                                     slot="page-${stage.objectUid}" | ||||||
|  |                                     data-tab-title="${ifDefined(stage.title)}" | ||||||
|  |                                     class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||||
|  |                                 > | ||||||
|  |                                     ${this.renderSourceSettings(stage)} | ||||||
|  |                                 </section>`; | ||||||
|  |                             }); | ||||||
|  |                         }), | ||||||
|  |                     )} | ||||||
|  |                 </ak-tabs> | ||||||
|  |             </main> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								web/src/user/user-settings/settings/BaseUserSettings.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/src/user/user-settings/settings/BaseUserSettings.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import { CSSResult, LitElement, property } from "lit-element"; | ||||||
|  | import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||||
|  | import PFCard from "@patternfly/patternfly/components/Card/card.css"; | ||||||
|  | import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||||||
|  | import AKGlobal from "../../../authentik.css"; | ||||||
|  | import PFForm from "@patternfly/patternfly/components/Form/form.css"; | ||||||
|  | import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | ||||||
|  |  | ||||||
|  | export abstract class BaseUserSettings extends LitElement { | ||||||
|  |     @property() | ||||||
|  |     objectId!: string; | ||||||
|  |  | ||||||
|  |     @property() | ||||||
|  |     configureUrl?: string; | ||||||
|  |  | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return [PFBase, PFCard, PFButton, PFForm, PFFormControl, AKGlobal]; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										50
									
								
								web/src/user/user-settings/settings/SourceSettingsOAuth.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								web/src/user/user-settings/settings/SourceSettingsOAuth.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | |||||||
|  | import { customElement, html, property, TemplateResult } from "lit-element"; | ||||||
|  | import { BaseUserSettings } from "./BaseUserSettings"; | ||||||
|  | import { SourcesApi } from "@goauthentik/api"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-settings-source-oauth") | ||||||
|  | export class SourceSettingsOAuth extends BaseUserSettings { | ||||||
|  |     @property() | ||||||
|  |     title!: string; | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-card"> | ||||||
|  |             <div class="pf-c-card__title">${t`Source ${this.title}`}</div> | ||||||
|  |             <div class="pf-c-card__body">${this.renderInner()}</div> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderInner(): TemplateResult { | ||||||
|  |         return html`${until( | ||||||
|  |             new SourcesApi(DEFAULT_CONFIG) | ||||||
|  |                 .sourcesUserConnectionsOauthList({ | ||||||
|  |                     sourceSlug: this.objectId, | ||||||
|  |                 }) | ||||||
|  |                 .then((connection) => { | ||||||
|  |                     if (connection.results.length > 0) { | ||||||
|  |                         return html`<p>${t`Connected.`}</p> | ||||||
|  |                             <button | ||||||
|  |                                 class="pf-c-button pf-m-danger" | ||||||
|  |                                 @click=${() => { | ||||||
|  |                                     return new SourcesApi( | ||||||
|  |                                         DEFAULT_CONFIG, | ||||||
|  |                                     ).sourcesUserConnectionsOauthDestroy({ | ||||||
|  |                                         id: connection.results[0].pk || 0, | ||||||
|  |                                     }); | ||||||
|  |                                 }} | ||||||
|  |                             > | ||||||
|  |                                 ${t`Disconnect`} | ||||||
|  |                             </button>`; | ||||||
|  |                     } | ||||||
|  |                     return html`<p>${t`Not connected.`}</p> | ||||||
|  |                         <a class="pf-c-button pf-m-primary" href=${ifDefined(this.configureUrl)}> | ||||||
|  |                             ${t`Connect`} | ||||||
|  |                         </a>`; | ||||||
|  |                 }), | ||||||
|  |         )}`; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								web/src/user/user-settings/settings/SourceSettingsPlex.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								web/src/user/user-settings/settings/SourceSettingsPlex.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | import { customElement, html, property, TemplateResult } from "lit-element"; | ||||||
|  | import { BaseUserSettings } from "./BaseUserSettings"; | ||||||
|  | import { SourcesApi } from "@goauthentik/api"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-settings-source-plex") | ||||||
|  | export class SourceSettingsPlex extends BaseUserSettings { | ||||||
|  |     @property() | ||||||
|  |     title!: string; | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-card"> | ||||||
|  |             <div class="pf-c-card__title">${t`Source ${this.title}`}</div> | ||||||
|  |             <div class="pf-c-card__body">${this.renderInner()}</div> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderInner(): TemplateResult { | ||||||
|  |         return html`${until( | ||||||
|  |             new SourcesApi(DEFAULT_CONFIG) | ||||||
|  |                 .sourcesUserConnectionsPlexList({ | ||||||
|  |                     sourceSlug: this.objectId, | ||||||
|  |                 }) | ||||||
|  |                 .then((connection) => { | ||||||
|  |                     if (connection.results.length > 0) { | ||||||
|  |                         return html`<p>${t`Connected.`}</p> | ||||||
|  |                             <button | ||||||
|  |                                 class="pf-c-button pf-m-danger" | ||||||
|  |                                 @click=${() => { | ||||||
|  |                                     return new SourcesApi( | ||||||
|  |                                         DEFAULT_CONFIG, | ||||||
|  |                                     ).sourcesUserConnectionsPlexDestroy({ | ||||||
|  |                                         id: connection.results[0].pk || 0, | ||||||
|  |                                     }); | ||||||
|  |                                 }} | ||||||
|  |                             > | ||||||
|  |                                 ${t`Disconnect`} | ||||||
|  |                             </button>`; | ||||||
|  |                     } | ||||||
|  |                     return html`<p>${t`Not connected.`}</p>`; | ||||||
|  |                 }), | ||||||
|  |         )}`; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,79 @@ | |||||||
|  | import { AuthenticatorsApi } from "@goauthentik/api"; | ||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { customElement, html, TemplateResult } from "lit-element"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { BaseUserSettings } from "./BaseUserSettings"; | ||||||
|  | import { EVENT_REFRESH } from "../../../constants"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-settings-authenticator-duo") | ||||||
|  | export class UserSettingsAuthenticatorDuo extends BaseUserSettings { | ||||||
|  |     renderEnabled(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-card__body"> | ||||||
|  |                 <p> | ||||||
|  |                     ${t`Status: Enabled`} | ||||||
|  |                     <i class="pf-icon pf-icon-ok"></i> | ||||||
|  |                 </p> | ||||||
|  |             </div> | ||||||
|  |             <div class="pf-c-card__footer"> | ||||||
|  |                 <button | ||||||
|  |                     class="pf-c-button pf-m-danger" | ||||||
|  |                     @click=${() => { | ||||||
|  |                         return new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                             .authenticatorsDuoList({}) | ||||||
|  |                             .then((devices) => { | ||||||
|  |                                 if (devices.results.length < 1) { | ||||||
|  |                                     return; | ||||||
|  |                                 } | ||||||
|  |                                 // TODO: Handle multiple devices, currently we assume only one TOTP Device | ||||||
|  |                                 return new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                                     .authenticatorsDuoDestroy({ | ||||||
|  |                                         id: devices.results[0].pk || 0, | ||||||
|  |                                     }) | ||||||
|  |                                     .then(() => { | ||||||
|  |                                         this.dispatchEvent( | ||||||
|  |                                             new CustomEvent(EVENT_REFRESH, { | ||||||
|  |                                                 bubbles: true, | ||||||
|  |                                                 composed: true, | ||||||
|  |                                             }), | ||||||
|  |                                         ); | ||||||
|  |                                     }); | ||||||
|  |                             }); | ||||||
|  |                     }} | ||||||
|  |                 > | ||||||
|  |                     ${t`Disable Duo authenticator`} | ||||||
|  |                 </button> | ||||||
|  |             </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderDisabled(): TemplateResult { | ||||||
|  |         return html` <div class="pf-c-card__body"> | ||||||
|  |                 <p> | ||||||
|  |                     ${t`Status: Disabled`} | ||||||
|  |                     <i class="pf-icon pf-icon-error-circle-o"></i> | ||||||
|  |                 </p> | ||||||
|  |             </div> | ||||||
|  |             <div class="pf-c-card__footer"> | ||||||
|  |                 ${this.configureUrl | ||||||
|  |                     ? html`<a | ||||||
|  |                           href="${this.configureUrl}?next=/%23%2Fuser" | ||||||
|  |                           class="pf-c-button pf-m-primary" | ||||||
|  |                           >${t`Enable Duo authenticator`} | ||||||
|  |                       </a>` | ||||||
|  |                     : html``} | ||||||
|  |             </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-card"> | ||||||
|  |             <div class="pf-c-card__title">${t`Duo`}</div> | ||||||
|  |             ${until( | ||||||
|  |                 new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsDuoList({}).then((devices) => { | ||||||
|  |                     return devices.results.length > 0 | ||||||
|  |                         ? this.renderEnabled() | ||||||
|  |                         : this.renderDisabled(); | ||||||
|  |                 }), | ||||||
|  |             )} | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,100 @@ | |||||||
|  | import { AuthenticatorsApi } from "@goauthentik/api"; | ||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { CSSResult, customElement, html, TemplateResult } from "lit-element"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { STATIC_TOKEN_STYLE } from "../../../flows/stages/authenticator_static/AuthenticatorStaticStage"; | ||||||
|  | import { BaseUserSettings } from "./BaseUserSettings"; | ||||||
|  | import { EVENT_REFRESH } from "../../../constants"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-settings-authenticator-static") | ||||||
|  | export class UserSettingsAuthenticatorStatic extends BaseUserSettings { | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return super.styles.concat(STATIC_TOKEN_STYLE); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderEnabled(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-card__body"> | ||||||
|  |                 <p> | ||||||
|  |                     ${t`Status: Enabled`} | ||||||
|  |                     <i class="pf-icon pf-icon-ok"></i> | ||||||
|  |                 </p> | ||||||
|  |                 <ul class="ak-otp-tokens"> | ||||||
|  |                     ${until( | ||||||
|  |                         new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                             .authenticatorsStaticList({}) | ||||||
|  |                             .then((devices) => { | ||||||
|  |                                 if (devices.results.length < 1) { | ||||||
|  |                                     return; | ||||||
|  |                                 } | ||||||
|  |                                 return devices.results[0].tokenSet?.map((token) => { | ||||||
|  |                                     return html`<li>${token.token}</li>`; | ||||||
|  |                                 }); | ||||||
|  |                             }), | ||||||
|  |                     )} | ||||||
|  |                 </ul> | ||||||
|  |             </div> | ||||||
|  |             <div class="pf-c-card__footer"> | ||||||
|  |                 <button | ||||||
|  |                     class="pf-c-button pf-m-danger" | ||||||
|  |                     @click=${() => { | ||||||
|  |                         return new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                             .authenticatorsStaticList({}) | ||||||
|  |                             .then((devices) => { | ||||||
|  |                                 if (devices.results.length < 1) { | ||||||
|  |                                     return; | ||||||
|  |                                 } | ||||||
|  |                                 // TODO: Handle multiple devices, currently we assume only one TOTP Device | ||||||
|  |                                 return new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                                     .authenticatorsStaticDestroy({ | ||||||
|  |                                         id: devices.results[0].pk || 0, | ||||||
|  |                                     }) | ||||||
|  |                                     .then(() => { | ||||||
|  |                                         this.dispatchEvent( | ||||||
|  |                                             new CustomEvent(EVENT_REFRESH, { | ||||||
|  |                                                 bubbles: true, | ||||||
|  |                                                 composed: true, | ||||||
|  |                                             }), | ||||||
|  |                                         ); | ||||||
|  |                                     }); | ||||||
|  |                             }); | ||||||
|  |                     }} | ||||||
|  |                 > | ||||||
|  |                     ${t`Disable Static Tokens`} | ||||||
|  |                 </button> | ||||||
|  |             </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderDisabled(): TemplateResult { | ||||||
|  |         return html` <div class="pf-c-card__body"> | ||||||
|  |                 <p> | ||||||
|  |                     ${t`Status: Disabled`} | ||||||
|  |                     <i class="pf-icon pf-icon-error-circle-o"></i> | ||||||
|  |                 </p> | ||||||
|  |             </div> | ||||||
|  |             <div class="pf-c-card__footer"> | ||||||
|  |                 ${this.configureUrl | ||||||
|  |                     ? html`<a | ||||||
|  |                           href="${this.configureUrl}?next=/%23%2Fuser" | ||||||
|  |                           class="pf-c-button pf-m-primary" | ||||||
|  |                           >${t`Enable Static Tokens`} | ||||||
|  |                       </a>` | ||||||
|  |                     : html``} | ||||||
|  |             </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-card"> | ||||||
|  |             <div class="pf-c-card__title">${t`Static tokens`}</div> | ||||||
|  |             ${until( | ||||||
|  |                 new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                     .authenticatorsStaticList({}) | ||||||
|  |                     .then((devices) => { | ||||||
|  |                         return devices.results.length > 0 | ||||||
|  |                             ? this.renderEnabled() | ||||||
|  |                             : this.renderDisabled(); | ||||||
|  |                     }), | ||||||
|  |             )} | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,79 @@ | |||||||
|  | import { AuthenticatorsApi } from "@goauthentik/api"; | ||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { customElement, html, TemplateResult } from "lit-element"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { BaseUserSettings } from "./BaseUserSettings"; | ||||||
|  | import { EVENT_REFRESH } from "../../../constants"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-settings-authenticator-totp") | ||||||
|  | export class UserSettingsAuthenticatorTOTP extends BaseUserSettings { | ||||||
|  |     renderEnabled(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-card__body"> | ||||||
|  |                 <p> | ||||||
|  |                     ${t`Status: Enabled`} | ||||||
|  |                     <i class="pf-icon pf-icon-ok"></i> | ||||||
|  |                 </p> | ||||||
|  |             </div> | ||||||
|  |             <div class="pf-c-card__footer"> | ||||||
|  |                 <button | ||||||
|  |                     class="pf-c-button pf-m-danger" | ||||||
|  |                     @click=${() => { | ||||||
|  |                         return new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                             .authenticatorsTotpList({}) | ||||||
|  |                             .then((devices) => { | ||||||
|  |                                 if (devices.results.length < 1) { | ||||||
|  |                                     return; | ||||||
|  |                                 } | ||||||
|  |                                 // TODO: Handle multiple devices, currently we assume only one TOTP Device | ||||||
|  |                                 return new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                                     .authenticatorsTotpDestroy({ | ||||||
|  |                                         id: devices.results[0].pk || 0, | ||||||
|  |                                     }) | ||||||
|  |                                     .then(() => { | ||||||
|  |                                         this.dispatchEvent( | ||||||
|  |                                             new CustomEvent(EVENT_REFRESH, { | ||||||
|  |                                                 bubbles: true, | ||||||
|  |                                                 composed: true, | ||||||
|  |                                             }), | ||||||
|  |                                         ); | ||||||
|  |                                     }); | ||||||
|  |                             }); | ||||||
|  |                     }} | ||||||
|  |                 > | ||||||
|  |                     ${t`Disable Time-based OTP`} | ||||||
|  |                 </button> | ||||||
|  |             </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderDisabled(): TemplateResult { | ||||||
|  |         return html` <div class="pf-c-card__body"> | ||||||
|  |                 <p> | ||||||
|  |                     ${t`Status: Disabled`} | ||||||
|  |                     <i class="pf-icon pf-icon-error-circle-o"></i> | ||||||
|  |                 </p> | ||||||
|  |             </div> | ||||||
|  |             <div class="pf-c-card__footer"> | ||||||
|  |                 ${this.configureUrl | ||||||
|  |                     ? html`<a | ||||||
|  |                           href="${this.configureUrl}?next=/%23%2Fuser" | ||||||
|  |                           class="pf-c-button pf-m-primary" | ||||||
|  |                           >${t`Enable TOTP`} | ||||||
|  |                       </a>` | ||||||
|  |                     : html``} | ||||||
|  |             </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-card"> | ||||||
|  |             <div class="pf-c-card__title">${t`Time-based One-Time Passwords`}</div> | ||||||
|  |             ${until( | ||||||
|  |                 new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsTotpList({}).then((devices) => { | ||||||
|  |                     return devices.results.length > 0 | ||||||
|  |                         ? this.renderEnabled() | ||||||
|  |                         : this.renderDisabled(); | ||||||
|  |                 }), | ||||||
|  |             )} | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,125 @@ | |||||||
|  | import { CSSResult, customElement, html, TemplateResult } from "lit-element"; | ||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { AuthenticatorsApi, WebAuthnDevice } from "@goauthentik/api"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { BaseUserSettings } from "./BaseUserSettings"; | ||||||
|  | import PFDataList from "@patternfly/patternfly/components/DataList/data-list.css"; | ||||||
|  | import "../../../elements/buttons/ModalButton"; | ||||||
|  | import "../../../elements/buttons/SpinnerButton"; | ||||||
|  | import "../../../elements/forms/DeleteForm"; | ||||||
|  | import "../../../elements/forms/Form"; | ||||||
|  | import "../../../elements/forms/ModalForm"; | ||||||
|  | import "../../../elements/forms/HorizontalFormElement"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | import { EVENT_REFRESH } from "../../../constants"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-settings-authenticator-webauthn") | ||||||
|  | export class UserSettingsAuthenticatorWebAuthn extends BaseUserSettings { | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return super.styles.concat(PFDataList); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderDelete(device: WebAuthnDevice): TemplateResult { | ||||||
|  |         return html`<ak-forms-delete | ||||||
|  |             .obj=${device} | ||||||
|  |             objectLabel=${t`Authenticator`} | ||||||
|  |             .delete=${() => { | ||||||
|  |                 return new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                     .authenticatorsWebauthnDestroy({ | ||||||
|  |                         id: device.pk || 0, | ||||||
|  |                     }) | ||||||
|  |                     .then(() => { | ||||||
|  |                         this.dispatchEvent( | ||||||
|  |                             new CustomEvent(EVENT_REFRESH, { | ||||||
|  |                                 bubbles: true, | ||||||
|  |                                 composed: true, | ||||||
|  |                             }), | ||||||
|  |                         ); | ||||||
|  |                     }); | ||||||
|  |             }} | ||||||
|  |         > | ||||||
|  |             <button slot="trigger" class="pf-c-button pf-m-danger">${t`Delete`}</button> | ||||||
|  |         </ak-forms-delete>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderUpdate(device: WebAuthnDevice): TemplateResult { | ||||||
|  |         return html`<ak-forms-modal> | ||||||
|  |             <span slot="submit"> ${t`Update`} </span> | ||||||
|  |             <span slot="header"> ${t`Update`} </span> | ||||||
|  |             <ak-form | ||||||
|  |                 slot="form" | ||||||
|  |                 successMessage=${t`Successfully updated device.`} | ||||||
|  |                 .send=${(data: unknown) => { | ||||||
|  |                     return new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                         .authenticatorsWebauthnUpdate({ | ||||||
|  |                             id: device.pk || 0, | ||||||
|  |                             webAuthnDeviceRequest: data as WebAuthnDevice, | ||||||
|  |                         }) | ||||||
|  |                         .then(() => { | ||||||
|  |                             this.requestUpdate(); | ||||||
|  |                         }); | ||||||
|  |                 }} | ||||||
|  |             > | ||||||
|  |                 <form class="pf-c-form pf-m-horizontal"> | ||||||
|  |                     <ak-form-element-horizontal | ||||||
|  |                         label=${t`Device name`} | ||||||
|  |                         ?required=${true} | ||||||
|  |                         name="name" | ||||||
|  |                     > | ||||||
|  |                         <input | ||||||
|  |                             type="text" | ||||||
|  |                             value="${ifDefined(device.name)}" | ||||||
|  |                             class="pf-c-form-control" | ||||||
|  |                             required | ||||||
|  |                         /> | ||||||
|  |                     </ak-form-element-horizontal> | ||||||
|  |                 </form> | ||||||
|  |             </ak-form> | ||||||
|  |             <button slot="trigger" class="pf-c-button pf-m-primary">${t`Update`}</button> | ||||||
|  |         </ak-forms-modal>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         return html`<div class="pf-c-card"> | ||||||
|  |             <div class="pf-c-card__title">${t`WebAuthn Devices`}</div> | ||||||
|  |             <div class="pf-c-card__body"> | ||||||
|  |                 <ul class="pf-c-data-list" role="list"> | ||||||
|  |                     ${until( | ||||||
|  |                         new AuthenticatorsApi(DEFAULT_CONFIG) | ||||||
|  |                             .authenticatorsWebauthnList({}) | ||||||
|  |                             .then((devices) => { | ||||||
|  |                                 return devices.results.map((device) => { | ||||||
|  |                                     return html`<li class="pf-c-data-list__item"> | ||||||
|  |                                         <div class="pf-c-data-list__item-row"> | ||||||
|  |                                             <div class="pf-c-data-list__item-content"> | ||||||
|  |                                                 <div class="pf-c-data-list__cell"> | ||||||
|  |                                                     ${device.name || "-"} | ||||||
|  |                                                 </div> | ||||||
|  |                                                 <div class="pf-c-data-list__cell"> | ||||||
|  |                                                     ${t`Created ${device.createdOn?.toLocaleString()}`} | ||||||
|  |                                                 </div> | ||||||
|  |                                                 <div class="pf-c-data-list__cell"> | ||||||
|  |                                                     ${this.renderUpdate(device)} | ||||||
|  |                                                     ${this.renderDelete(device)} | ||||||
|  |                                                 </div> | ||||||
|  |                                             </div> | ||||||
|  |                                         </div> | ||||||
|  |                                     </li>`; | ||||||
|  |                                 }); | ||||||
|  |                             }), | ||||||
|  |                     )} | ||||||
|  |                 </ul> | ||||||
|  |             </div> | ||||||
|  |             <div class="pf-c-card__footer"> | ||||||
|  |                 ${this.configureUrl | ||||||
|  |                     ? html`<a | ||||||
|  |                           href="${this.configureUrl}?next=/%23%2Fuser" | ||||||
|  |                           class="pf-c-button pf-m-primary" | ||||||
|  |                           >${t`Configure WebAuthn`} | ||||||
|  |                       </a>` | ||||||
|  |                     : html``} | ||||||
|  |             </div> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								web/src/user/user-settings/settings/UserSettingsPassword.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								web/src/user/user-settings/settings/UserSettingsPassword.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | import { customElement, html, TemplateResult } from "lit-element"; | ||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { BaseUserSettings } from "./BaseUserSettings"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-settings-password") | ||||||
|  | export class UserSettingsPassword extends BaseUserSettings { | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         // For this stage we don't need to check for a configureFlow, | ||||||
|  |         // as the stage won't return any UI Elements if no configureFlow is set. | ||||||
|  |         return html`<div class="pf-c-card"> | ||||||
|  |             <div class="pf-c-card__title">${t`Change your password`}</div> | ||||||
|  |             <div class="pf-c-card__body"> | ||||||
|  |                 <a href="${ifDefined(this.configureUrl)}" class="pf-c-button pf-m-primary"> | ||||||
|  |                     ${t`Change password`} | ||||||
|  |                 </a> | ||||||
|  |             </div> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								web/src/user/user-settings/tokens/UserTokenForm.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								web/src/user/user-settings/tokens/UserTokenForm.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | |||||||
|  | import { CoreApi, IntentEnum, Token } from "@goauthentik/api"; | ||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { customElement, property } from "lit-element"; | ||||||
|  | import { html, TemplateResult } from "lit-html"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | import "../../../elements/forms/HorizontalFormElement"; | ||||||
|  | import { ModelForm } from "../../../elements/forms/ModelForm"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-token-form") | ||||||
|  | export class UserTokenForm extends ModelForm<Token, string> { | ||||||
|  |     @property() | ||||||
|  |     intent: IntentEnum = IntentEnum.Api; | ||||||
|  |  | ||||||
|  |     loadInstance(pk: string): Promise<Token> { | ||||||
|  |         return new CoreApi(DEFAULT_CONFIG).coreTokensRetrieve({ | ||||||
|  |             identifier: pk, | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getSuccessMessage(): string { | ||||||
|  |         if (this.instance) { | ||||||
|  |             return t`Successfully updated token.`; | ||||||
|  |         } else { | ||||||
|  |             return t`Successfully created token.`; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send = (data: Token): Promise<Token> => { | ||||||
|  |         if (this.instance) { | ||||||
|  |             return new CoreApi(DEFAULT_CONFIG).coreTokensUpdate({ | ||||||
|  |                 identifier: this.instance.identifier, | ||||||
|  |                 tokenRequest: data, | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             data.intent = this.intent; | ||||||
|  |             return new CoreApi(DEFAULT_CONFIG).coreTokensCreate({ | ||||||
|  |                 tokenRequest: data, | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     renderForm(): TemplateResult { | ||||||
|  |         return html`<form class="pf-c-form pf-m-horizontal"> | ||||||
|  |             <ak-form-element-horizontal label=${t`Identifier`} ?required=${true} name="identifier"> | ||||||
|  |                 <input | ||||||
|  |                     type="text" | ||||||
|  |                     value="${ifDefined(this.instance?.identifier)}" | ||||||
|  |                     class="pf-c-form-control" | ||||||
|  |                     required | ||||||
|  |                 /> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal label=${t`Description`} name="description"> | ||||||
|  |                 <input | ||||||
|  |                     type="text" | ||||||
|  |                     value="${ifDefined(this.instance?.description)}" | ||||||
|  |                     class="pf-c-form-control" | ||||||
|  |                 /> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |         </form>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										156
									
								
								web/src/user/user-settings/tokens/UserTokenList.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								web/src/user/user-settings/tokens/UserTokenList.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,156 @@ | |||||||
|  | import { t } from "@lingui/macro"; | ||||||
|  | import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; | ||||||
|  | import { AKResponse } from "../../../api/Client"; | ||||||
|  | import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; | ||||||
|  |  | ||||||
|  | import "../../../elements/forms/DeleteBulkForm"; | ||||||
|  | import "../../../elements/forms/ModalForm"; | ||||||
|  | import "../../../elements/buttons/ModalButton"; | ||||||
|  | import "../../../elements/buttons/Dropdown"; | ||||||
|  | import "../../../elements/buttons/TokenCopyButton"; | ||||||
|  | import { Table, TableColumn } from "../../../elements/table/Table"; | ||||||
|  | import { PAGE_SIZE } from "../../../constants"; | ||||||
|  | import { CoreApi, IntentEnum, Token } from "@goauthentik/api"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import "./UserTokenForm"; | ||||||
|  | import { IntentToLabel } from "../../../pages/tokens/TokenListPage"; | ||||||
|  |  | ||||||
|  | @customElement("ak-user-token-list") | ||||||
|  | export class UserTokenList extends Table<Token> { | ||||||
|  |     searchEnabled(): boolean { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     expandable = true; | ||||||
|  |     checkbox = true; | ||||||
|  |  | ||||||
|  |     @property() | ||||||
|  |     order = "expires"; | ||||||
|  |  | ||||||
|  |     apiEndpoint(page: number): Promise<AKResponse<Token>> { | ||||||
|  |         return new CoreApi(DEFAULT_CONFIG).coreTokensList({ | ||||||
|  |             ordering: this.order, | ||||||
|  |             page: page, | ||||||
|  |             pageSize: PAGE_SIZE, | ||||||
|  |             search: this.search || "", | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     columns(): TableColumn[] { | ||||||
|  |         return [new TableColumn(t`Identifier`, "identifier"), new TableColumn("")]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return super.styles.concat(PFDescriptionList); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderToolbar(): TemplateResult { | ||||||
|  |         return html` | ||||||
|  |             <ak-forms-modal> | ||||||
|  |                 <span slot="submit"> ${t`Create`} </span> | ||||||
|  |                 <span slot="header"> ${t`Create Token`} </span> | ||||||
|  |                 <ak-user-token-form intent=${IntentEnum.Api} slot="form"> </ak-user-token-form> | ||||||
|  |                 <button slot="trigger" class="pf-c-button pf-m-secondary"> | ||||||
|  |                     ${t`Create Token`} | ||||||
|  |                 </button> | ||||||
|  |             </ak-forms-modal> | ||||||
|  |             <ak-forms-modal> | ||||||
|  |                 <span slot="submit"> ${t`Create`} </span> | ||||||
|  |                 <span slot="header"> ${t`Create App password`} </span> | ||||||
|  |                 <ak-user-token-form intent=${IntentEnum.AppPassword} slot="form"> | ||||||
|  |                 </ak-user-token-form> | ||||||
|  |                 <button slot="trigger" class="pf-c-button pf-m-secondary"> | ||||||
|  |                     ${t`Create App password`} | ||||||
|  |                 </button> | ||||||
|  |             </ak-forms-modal> | ||||||
|  |             ${super.renderToolbar()} | ||||||
|  |         `; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderExpanded(item: Token): TemplateResult { | ||||||
|  |         return html` <td role="cell" colspan="3"> | ||||||
|  |                 <div class="pf-c-table__expandable-row-content"> | ||||||
|  |                     <dl class="pf-c-description-list pf-m-horizontal"> | ||||||
|  |                         <div class="pf-c-description-list__group"> | ||||||
|  |                             <dt class="pf-c-description-list__term"> | ||||||
|  |                                 <span class="pf-c-description-list__text">${t`User`}</span> | ||||||
|  |                             </dt> | ||||||
|  |                             <dd class="pf-c-description-list__description"> | ||||||
|  |                                 <div class="pf-c-description-list__text"> | ||||||
|  |                                     ${item.user?.username} | ||||||
|  |                                 </div> | ||||||
|  |                             </dd> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="pf-c-description-list__group"> | ||||||
|  |                             <dt class="pf-c-description-list__term"> | ||||||
|  |                                 <span class="pf-c-description-list__text">${t`Expiring`}</span> | ||||||
|  |                             </dt> | ||||||
|  |                             <dd class="pf-c-description-list__description"> | ||||||
|  |                                 <div class="pf-c-description-list__text"> | ||||||
|  |                                     ${item.expiring ? t`Yes` : t`No`} | ||||||
|  |                                 </div> | ||||||
|  |                             </dd> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="pf-c-description-list__group"> | ||||||
|  |                             <dt class="pf-c-description-list__term"> | ||||||
|  |                                 <span class="pf-c-description-list__text">${t`Expiring`}</span> | ||||||
|  |                             </dt> | ||||||
|  |                             <dd class="pf-c-description-list__description"> | ||||||
|  |                                 <div class="pf-c-description-list__text"> | ||||||
|  |                                     ${item.expiring ? item.expires?.toLocaleString() : "-"} | ||||||
|  |                                 </div> | ||||||
|  |                             </dd> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="pf-c-description-list__group"> | ||||||
|  |                             <dt class="pf-c-description-list__term"> | ||||||
|  |                                 <span class="pf-c-description-list__text">${t`Intent`}</span> | ||||||
|  |                             </dt> | ||||||
|  |                             <dd class="pf-c-description-list__description"> | ||||||
|  |                                 <div class="pf-c-description-list__text"> | ||||||
|  |                                     ${IntentToLabel(item.intent || IntentEnum.Api)} | ||||||
|  |                                 </div> | ||||||
|  |                             </dd> | ||||||
|  |                         </div> | ||||||
|  |                     </dl> | ||||||
|  |                 </div> | ||||||
|  |             </td> | ||||||
|  |             <td></td>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderToolbarSelected(): TemplateResult { | ||||||
|  |         const disabled = this.selectedElements.length < 1; | ||||||
|  |         return html`<ak-forms-delete-bulk | ||||||
|  |             objectLabel=${t`Token(s)`} | ||||||
|  |             .objects=${this.selectedElements} | ||||||
|  |             .delete=${(item: Token) => { | ||||||
|  |                 return new CoreApi(DEFAULT_CONFIG).coreTokensDestroy({ | ||||||
|  |                     identifier: item.identifier, | ||||||
|  |                 }); | ||||||
|  |             }} | ||||||
|  |         > | ||||||
|  |             <button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger"> | ||||||
|  |                 ${t`Delete`} | ||||||
|  |             </button> | ||||||
|  |         </ak-forms-delete-bulk>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     row(item: Token): TemplateResult[] { | ||||||
|  |         return [ | ||||||
|  |             html`${item.identifier}`, | ||||||
|  |             html` | ||||||
|  |                 <ak-forms-modal> | ||||||
|  |                     <span slot="submit"> ${t`Update`} </span> | ||||||
|  |                     <span slot="header"> ${t`Update Token`} </span> | ||||||
|  |                     <ak-user-token-form slot="form" .instancePk=${item.identifier}> | ||||||
|  |                     </ak-user-token-form> | ||||||
|  |                     <button slot="trigger" class="pf-c-button pf-m-plain"> | ||||||
|  |                         <i class="fas fa-edit"></i> | ||||||
|  |                     </button> | ||||||
|  |                 </ak-forms-modal> | ||||||
|  |                 <ak-token-copy-button identifier="${item.identifier}"> | ||||||
|  |                     ${t`Copy Key`} | ||||||
|  |                 </ak-token-copy-button> | ||||||
|  |             `, | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Jens L
					Jens L