Compare commits
29 Commits
website/do
...
web/add-co
Author | SHA1 | Date | |
---|---|---|---|
00c1e17b52 | |||
3c2ce40afd | |||
2aceed285e | |||
81e5fef667 | |||
7aa6593760 | |||
c40a17beb9 | |||
335c9fbc10 | |||
51b53caf61 | |||
989100a900 | |||
8e1531d051 | |||
f6f37d6d92 | |||
5b6ca70f22 | |||
a74674c3d6 | |||
f46984dec4 | |||
c7963e4af7 | |||
6e30b11974 | |||
13bd4069e4 | |||
cba8e84bbe | |||
d313fd7fb4 | |||
102811508f | |||
16b3ca3715 | |||
8b4e0361c4 | |||
22cb5b7379 | |||
2d0117d096 | |||
035bda4eac | |||
50906214e5 | |||
e505f274b6 | |||
fe52f44dca | |||
3146e5a50f |
@ -75,7 +75,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
||||
/bin/sh -c "GEOIPUPDATE_LICENSE_KEY_FILE=/run/secrets/GEOIPUPDATE_LICENSE_KEY /usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
|
||||
|
||||
# Stage 4: Download uv
|
||||
FROM ghcr.io/astral-sh/uv:0.7.12 AS uv
|
||||
FROM ghcr.io/astral-sh/uv:0.7.13 AS uv
|
||||
# Stage 5: Base python image
|
||||
FROM ghcr.io/goauthentik/fips-python:3.13.4-slim-bookworm-fips AS python-base
|
||||
|
||||
|
@ -134,7 +134,7 @@ class Command(BaseCommand):
|
||||
"id": {"type": "string"},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"enum": [s.value for s in BlueprintEntryDesiredState],
|
||||
"enum": sorted([s.value for s in BlueprintEntryDesiredState]),
|
||||
"default": "present",
|
||||
},
|
||||
"conditions": {"type": "array", "items": {"type": "boolean"}},
|
||||
@ -205,7 +205,7 @@ class Command(BaseCommand):
|
||||
"type": "object",
|
||||
"required": ["permission"],
|
||||
"properties": {
|
||||
"permission": {"type": "string", "enum": perms},
|
||||
"permission": {"type": "string", "enum": sorted(perms)},
|
||||
"user": {"type": "integer"},
|
||||
"role": {"type": "string"},
|
||||
},
|
||||
|
@ -47,7 +47,7 @@ class MetaModelRegistry:
|
||||
models = apps.get_models()
|
||||
for _, value in self.models.items():
|
||||
models.append(value)
|
||||
return models
|
||||
return sorted(models, key=str)
|
||||
|
||||
def get_model(self, app_label: str, model_id: str) -> type[Model]:
|
||||
"""Get model checks if any virtual models are registered, and falls back
|
||||
|
@ -1,11 +1,9 @@
|
||||
"""Websocket tests"""
|
||||
|
||||
from dataclasses import asdict
|
||||
from unittest.mock import patch
|
||||
|
||||
from channels.routing import URLRouter
|
||||
from channels.testing import WebsocketCommunicator
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.test import TransactionTestCase
|
||||
|
||||
from authentik import __version__
|
||||
@ -16,12 +14,6 @@ from authentik.providers.proxy.models import ProxyProvider
|
||||
from authentik.root import websocket
|
||||
|
||||
|
||||
def patched__get_ct_cached(app_label, codename):
|
||||
"""Caches `ContentType` instances like its `QuerySet` does."""
|
||||
return ContentType.objects.get(app_label=app_label, permission__codename=codename)
|
||||
|
||||
|
||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
||||
class TestOutpostWS(TransactionTestCase):
|
||||
"""Websocket tests"""
|
||||
|
||||
|
@ -20,6 +20,9 @@ from authentik.lib.utils.time import timedelta_from_string
|
||||
from authentik.policies.engine import PolicyEngine
|
||||
from authentik.policies.views import PolicyAccessView
|
||||
from authentik.providers.rac.models import ConnectionToken, Endpoint, RACProvider
|
||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||
|
||||
PLAN_CONNECTION_SETTINGS = "connection_settings"
|
||||
|
||||
|
||||
class RACStartView(PolicyAccessView):
|
||||
@ -109,10 +112,15 @@ class RACFinalStage(RedirectStage):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_challenge(self, *args, **kwargs) -> RedirectChallenge:
|
||||
settings = self.executor.plan.context.get(PLAN_CONNECTION_SETTINGS)
|
||||
if not settings:
|
||||
settings = self.executor.plan.context.get(PLAN_CONTEXT_PROMPT, {}).get(
|
||||
PLAN_CONNECTION_SETTINGS
|
||||
)
|
||||
token = ConnectionToken.objects.create(
|
||||
provider=self.provider,
|
||||
endpoint=self.endpoint,
|
||||
settings=self.executor.plan.context.get("connection_settings", {}),
|
||||
settings=settings or {},
|
||||
session=self.request.session["authenticatedsession"],
|
||||
expires=now() + timedelta_from_string(self.provider.connection_expiry),
|
||||
expiring=True,
|
||||
|
@ -3,21 +3,38 @@
|
||||
import os
|
||||
from argparse import ArgumentParser
|
||||
from unittest import TestCase
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.test.runner import DiscoverRunner
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.lib.sentry import sentry_init
|
||||
from authentik.root.signals import post_startup, pre_startup, startup
|
||||
from tests.e2e.utils import get_docker_tag
|
||||
|
||||
# globally set maxDiff to none to show full assert error
|
||||
TestCase.maxDiff = None
|
||||
|
||||
|
||||
def get_docker_tag() -> str:
|
||||
"""Get docker-tag based off of CI variables"""
|
||||
env_pr_branch = "GITHUB_HEAD_REF"
|
||||
default_branch = "GITHUB_REF"
|
||||
branch_name = os.environ.get(default_branch, "main")
|
||||
if os.environ.get(env_pr_branch, "") != "":
|
||||
branch_name = os.environ[env_pr_branch]
|
||||
branch_name = branch_name.replace("refs/heads/", "").replace("/", "-")
|
||||
return f"gh-{branch_name}"
|
||||
|
||||
|
||||
def patched__get_ct_cached(app_label, codename):
|
||||
"""Caches `ContentType` instances like its `QuerySet` does."""
|
||||
return ContentType.objects.get(app_label=app_label, permission__codename=codename)
|
||||
|
||||
|
||||
class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
||||
"""Runs pytest to discover and run tests."""
|
||||
|
||||
@ -149,8 +166,9 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
||||
return 1
|
||||
|
||||
self.logger.info("Running tests", test_files=self.args)
|
||||
try:
|
||||
return pytest.main(self.args)
|
||||
except Exception as e:
|
||||
self.logger.error("Error running tests", error=str(e), test_files=self.args)
|
||||
return 1
|
||||
with patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached):
|
||||
try:
|
||||
return pytest.main(self.args)
|
||||
except Exception as e:
|
||||
self.logger.error("Error running tests", error=str(e), test_files=self.args)
|
||||
return 1
|
||||
|
12574
blueprints/schema.json
12574
blueprints/schema.json
File diff suppressed because it is too large
Load Diff
8
lifecycle/aws/package-lock.json
generated
8
lifecycle/aws/package-lock.json
generated
@ -9,7 +9,7 @@
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"aws-cdk": "^2.1018.0",
|
||||
"aws-cdk": "^2.1018.1",
|
||||
"cross-env": "^7.0.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -17,9 +17,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/aws-cdk": {
|
||||
"version": "2.1018.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1018.0.tgz",
|
||||
"integrity": "sha512-sppVsNtFJTW4wawS/PBudHCSNHb8xwaZ2WX1mpsfwaPNyTWm0eSUVJsRbRiRBu9O/Us8pgrd4woUjfM1lgD7Kw==",
|
||||
"version": "2.1018.1",
|
||||
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1018.1.tgz",
|
||||
"integrity": "sha512-kFPRox5kSm+ktJ451o0ng9rD+60p5Kt1CZIWw8kXnvqbsxN2xv6qbmyWSXw7sGVXVwqrRKVj+71/JeDr+LMAZw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
@ -10,7 +10,7 @@
|
||||
"node": ">=20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"aws-cdk": "^2.1018.0",
|
||||
"aws-cdk": "^2.1018.1",
|
||||
"cross-env": "^7.0.3"
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ dependencies = [
|
||||
"gunicorn==23.0.0",
|
||||
"jsonpatch==1.33",
|
||||
"jwcrypto==1.5.6",
|
||||
"kubernetes==32.0.1",
|
||||
"kubernetes==33.1.0",
|
||||
"ldap3==2.9.1",
|
||||
"lxml==5.4.0",
|
||||
"msgraph-sdk==1.33.0",
|
||||
@ -56,13 +56,13 @@ dependencies = [
|
||||
"pyyaml==6.0.2",
|
||||
"requests-oauthlib==2.0.0",
|
||||
"scim2-filter-parser==0.7.0",
|
||||
"sentry-sdk==2.29.1",
|
||||
"sentry-sdk==2.30.0",
|
||||
"service-identity==24.2.0",
|
||||
"setproctitle==1.3.6",
|
||||
"structlog==25.4.0",
|
||||
"swagger-spec-validator==3.0.4",
|
||||
"tenant-schemas-celery==3.0.0",
|
||||
"twilio==9.6.2",
|
||||
"twilio==9.6.3",
|
||||
"ua-parser==1.0.1",
|
||||
"unidecode==1.4.0",
|
||||
"urllib3<3",
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
from dataclasses import asdict
|
||||
from time import sleep
|
||||
from unittest.mock import patch
|
||||
|
||||
from guardian.shortcuts import assign_perm
|
||||
from ldap3 import ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE, Connection, Server
|
||||
@ -16,12 +15,10 @@ from authentik.flows.models import Flow
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.outposts.apps import MANAGED_OUTPOST
|
||||
from authentik.outposts.models import Outpost, OutpostConfig, OutpostType
|
||||
from authentik.outposts.tests.test_ws import patched__get_ct_cached
|
||||
from authentik.providers.ldap.models import APIAccessMode, LDAPProvider
|
||||
from tests.e2e.utils import SeleniumTestCase, retry
|
||||
|
||||
|
||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
||||
class TestProviderLDAP(SeleniumTestCase):
|
||||
"""LDAP and Outpost e2e tests"""
|
||||
|
||||
|
@ -6,7 +6,6 @@ from json import loads
|
||||
from sys import platform
|
||||
from time import sleep
|
||||
from unittest.case import skip, skipUnless
|
||||
from unittest.mock import patch
|
||||
|
||||
from channels.testing import ChannelsLiveServerTestCase
|
||||
from jwt import decode
|
||||
@ -18,12 +17,10 @@ from authentik.flows.models import Flow
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.outposts.models import DockerServiceConnection, Outpost, OutpostConfig, OutpostType
|
||||
from authentik.outposts.tasks import outpost_connection_discovery
|
||||
from authentik.outposts.tests.test_ws import patched__get_ct_cached
|
||||
from authentik.providers.proxy.models import ProxyProvider
|
||||
from tests.e2e.utils import SeleniumTestCase, retry
|
||||
|
||||
|
||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
||||
class TestProviderProxy(SeleniumTestCase):
|
||||
"""Proxy and Outpost e2e tests"""
|
||||
|
||||
|
@ -4,7 +4,6 @@ from json import loads
|
||||
from pathlib import Path
|
||||
from time import sleep
|
||||
from unittest import skip
|
||||
from unittest.mock import patch
|
||||
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
@ -13,12 +12,10 @@ from authentik.core.models import Application
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.outposts.models import Outpost, OutpostType
|
||||
from authentik.outposts.tests.test_ws import patched__get_ct_cached
|
||||
from authentik.providers.proxy.models import ProxyMode, ProxyProvider
|
||||
from tests.e2e.utils import SeleniumTestCase, retry
|
||||
|
||||
|
||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
||||
class TestProviderProxyForward(SeleniumTestCase):
|
||||
"""Proxy and Outpost e2e tests"""
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
from dataclasses import asdict
|
||||
from time import sleep
|
||||
from unittest.mock import patch
|
||||
|
||||
from pyrad.client import Client
|
||||
from pyrad.dictionary import Dictionary
|
||||
@ -13,12 +12,10 @@ from authentik.core.models import Application, User
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.lib.generators import generate_id, generate_key
|
||||
from authentik.outposts.models import Outpost, OutpostConfig, OutpostType
|
||||
from authentik.outposts.tests.test_ws import patched__get_ct_cached
|
||||
from authentik.providers.radius.models import RadiusProvider
|
||||
from tests.e2e.utils import SeleniumTestCase, retry
|
||||
|
||||
|
||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
||||
class TestProviderRadius(SeleniumTestCase):
|
||||
"""Radius Outpost e2e tests"""
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
"""authentik e2e testing utilities"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
from collections.abc import Callable
|
||||
from functools import lru_cache, wraps
|
||||
@ -37,22 +36,12 @@ from authentik.core.api.users import UserSerializer
|
||||
from authentik.core.models import User
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.root.test_runner import get_docker_tag
|
||||
|
||||
IS_CI = "CI" in environ
|
||||
RETRIES = int(environ.get("RETRIES", "3")) if IS_CI else 1
|
||||
|
||||
|
||||
def get_docker_tag() -> str:
|
||||
"""Get docker-tag based off of CI variables"""
|
||||
env_pr_branch = "GITHUB_HEAD_REF"
|
||||
default_branch = "GITHUB_REF"
|
||||
branch_name = os.environ.get(default_branch, "main")
|
||||
if os.environ.get(env_pr_branch, "") != "":
|
||||
branch_name = os.environ[env_pr_branch]
|
||||
branch_name = branch_name.replace("refs/heads/", "").replace("/", "-")
|
||||
return f"gh-{branch_name}"
|
||||
|
||||
|
||||
def get_local_ip() -> str:
|
||||
"""Get the local machine's IP"""
|
||||
hostname = socket.gethostname()
|
||||
|
24
uv.lock
generated
24
uv.lock
generated
@ -301,7 +301,7 @@ requires-dist = [
|
||||
{ name = "gunicorn", specifier = "==23.0.0" },
|
||||
{ name = "jsonpatch", specifier = "==1.33" },
|
||||
{ name = "jwcrypto", specifier = "==1.5.6" },
|
||||
{ name = "kubernetes", specifier = "==32.0.1" },
|
||||
{ name = "kubernetes", specifier = "==33.1.0" },
|
||||
{ name = "ldap3", specifier = "==2.9.1" },
|
||||
{ name = "lxml", specifier = "==5.4.0" },
|
||||
{ name = "msgraph-sdk", specifier = "==1.33.0" },
|
||||
@ -317,13 +317,13 @@ requires-dist = [
|
||||
{ name = "pyyaml", specifier = "==6.0.2" },
|
||||
{ name = "requests-oauthlib", specifier = "==2.0.0" },
|
||||
{ name = "scim2-filter-parser", specifier = "==0.7.0" },
|
||||
{ name = "sentry-sdk", specifier = "==2.29.1" },
|
||||
{ name = "sentry-sdk", specifier = "==2.30.0" },
|
||||
{ name = "service-identity", specifier = "==24.2.0" },
|
||||
{ name = "setproctitle", specifier = "==1.3.6" },
|
||||
{ name = "structlog", specifier = "==25.4.0" },
|
||||
{ name = "swagger-spec-validator", specifier = "==3.0.4" },
|
||||
{ name = "tenant-schemas-celery", specifier = "==3.0.0" },
|
||||
{ name = "twilio", specifier = "==9.6.2" },
|
||||
{ name = "twilio", specifier = "==9.6.3" },
|
||||
{ name = "ua-parser", specifier = "==1.0.1" },
|
||||
{ name = "unidecode", specifier = "==1.4.0" },
|
||||
{ name = "urllib3", specifier = "<3" },
|
||||
@ -1772,7 +1772,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "kubernetes"
|
||||
version = "32.0.1"
|
||||
version = "33.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
@ -1787,9 +1787,9 @@ dependencies = [
|
||||
{ name = "urllib3" },
|
||||
{ name = "websocket-client" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b7/e8/0598f0e8b4af37cd9b10d8b87386cf3173cb8045d834ab5f6ec347a758b3/kubernetes-32.0.1.tar.gz", hash = "sha256:42f43d49abd437ada79a79a16bd48a604d3471a117a8347e87db693f2ba0ba28", size = 946691, upload-time = "2025-02-18T21:06:34.148Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ae/52/19ebe8004c243fdfa78268a96727c71e08f00ff6fe69a301d0b7fcbce3c2/kubernetes-33.1.0.tar.gz", hash = "sha256:f64d829843a54c251061a8e7a14523b521f2dc5c896cf6d65ccf348648a88993", size = 1036779, upload-time = "2025-06-09T21:57:58.521Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/08/10/9f8af3e6f569685ce3af7faab51c8dd9d93b9c38eba339ca31c746119447/kubernetes-32.0.1-py2.py3-none-any.whl", hash = "sha256:35282ab8493b938b08ab5526c7ce66588232df00ef5e1dbe88a419107dc10998", size = 1988070, upload-time = "2025-02-18T21:06:31.391Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/43/d9bebfc3db7dea6ec80df5cb2aad8d274dd18ec2edd6c4f21f32c237cbbb/kubernetes-33.1.0-py2.py3-none-any.whl", hash = "sha256:544de42b24b64287f7e0aa9513c93cb503f7f40eea39b20f66810011a86eabc5", size = 1941335, upload-time = "2025-06-09T21:57:56.327Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2931,15 +2931,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "2.29.1"
|
||||
version = "2.30.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "urllib3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/22/67/d552a5f8e5a6a56b2feea6529e2d8ccd54349084c84176d5a1f7295044bc/sentry_sdk-2.29.1.tar.gz", hash = "sha256:8d4a0206b95fa5fe85e5e7517ed662e3888374bdc342c00e435e10e6d831aa6d", size = 325518, upload-time = "2025-05-19T14:27:38.512Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/04/4c/af31e0201b48469786ddeb1bf6fd3dfa3a291cc613a0fe6a60163a7535f9/sentry_sdk-2.30.0.tar.gz", hash = "sha256:436369b02afef7430efb10300a344fb61a11fe6db41c2b11f41ee037d2dd7f45", size = 326767, upload-time = "2025-06-12T10:34:34.733Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/e5/da07b0bd832cefd52d16f2b9bbbe31624d57552602c06631686b93ccb1bd/sentry_sdk-2.29.1-py2.py3-none-any.whl", hash = "sha256:90862fe0616ded4572da6c9dadb363121a1ae49a49e21c418f0634e9d10b4c19", size = 341553, upload-time = "2025-05-19T14:27:36.882Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/99/31ac6faaae33ea698086692638f58d14f121162a8db0039e68e94135e7f1/sentry_sdk-2.30.0-py2.py3-none-any.whl", hash = "sha256:59391db1550662f746ea09b483806a631c3ae38d6340804a1a4c0605044f6877", size = 343149, upload-time = "2025-06-12T10:34:32.896Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3151,7 +3151,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "twilio"
|
||||
version = "9.6.2"
|
||||
version = "9.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
@ -3159,9 +3159,9 @@ dependencies = [
|
||||
{ name = "pyjwt" },
|
||||
{ name = "requests" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fa/c9/441a07f6552f2b504812501d56c41bd85b02afeef6c23ab8baf41ed6c70e/twilio-9.6.2.tar.gz", hash = "sha256:5da13bb497e39ece34cb9f2b3bc911f3288928612748f7688b3bda262c2767a1", size = 1041300, upload-time = "2025-05-29T12:25:04.59Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fb/af/1b401bc4cfd3eb41c7e2a98d0040d2bcfd2ad3217f3163401121179b3fb3/twilio-9.6.3.tar.gz", hash = "sha256:16a8c2ab9550343c25c8a195f31db9e230d9b341eca31ebdd301109910fd9730", size = 1041494, upload-time = "2025-06-12T10:40:55.63Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/67/91/382e83e5d205a7ae4325b66d40cd2fa6ce85526f2ed8fc553265e19abbe4/twilio-9.6.2-py2.py3-none-any.whl", hash = "sha256:8d4af6f42850734a921857df42940f7fed84e3e4a508d0d6bef5b9fb7dc08357", size = 1909253, upload-time = "2025-05-29T12:25:02.521Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/35/d61a3581eb223e5e1fc0add1c397d7bb60014b22790e8f89aa5eb4e41e04/twilio-9.6.3-py2.py3-none-any.whl", hash = "sha256:a9b2cf11b0718394f12c43585ca25b9094f12b82ff975f1561fcec7f0f6f49b2", size = 1909549, upload-time = "2025-06-12T10:40:53.67Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
201
web/package-lock.json
generated
201
web/package-lock.json
generated
@ -31,8 +31,8 @@
|
||||
"@open-wc/lit-helpers": "^0.7.0",
|
||||
"@patternfly/elements": "^4.1.0",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@sentry/browser": "^9.28.0",
|
||||
"@spotlightjs/spotlight": "^2.13.3",
|
||||
"@sentry/browser": "^9.28.1",
|
||||
"@spotlightjs/spotlight": "^3.0.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"change-case": "^5.4.4",
|
||||
@ -51,6 +51,7 @@
|
||||
"lit": "^3.2.0",
|
||||
"md-front-matter": "^1.0.4",
|
||||
"mermaid": "^11.6.0",
|
||||
"ninja-keys": "^1.2.2",
|
||||
"rapidoc": "^9.3.8",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
@ -2587,6 +2588,57 @@
|
||||
"@lit/reactive-element": "^1.0.0 || ^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@material/mwc-icon": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@material/mwc-icon/-/mwc-icon-0.25.3.tgz",
|
||||
"integrity": "sha512-36076AWZIRSr8qYOLjuDDkxej/HA0XAosrj7TS1ZeLlUBnLUtbDtvc1S7KSa0hqez7ouzOqGaWK24yoNnTa2OA==",
|
||||
"deprecated": "MWC beta is longer supported. Please upgrade to @material/web",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"lit": "^2.0.0",
|
||||
"tslib": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@material/mwc-icon/node_modules/@lit/reactive-element": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz",
|
||||
"integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@lit-labs/ssr-dom-shim": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@material/mwc-icon/node_modules/lit": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/lit/-/lit-2.8.0.tgz",
|
||||
"integrity": "sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@lit/reactive-element": "^1.6.0",
|
||||
"lit-element": "^3.3.0",
|
||||
"lit-html": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@material/mwc-icon/node_modules/lit-element": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.3.3.tgz",
|
||||
"integrity": "sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@lit-labs/ssr-dom-shim": "^1.1.0",
|
||||
"@lit/reactive-element": "^1.3.0",
|
||||
"lit-html": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@material/mwc-icon/node_modules/lit-html": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.8.0.tgz",
|
||||
"integrity": "sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@types/trusted-types": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@mdx-js/mdx": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.0.tgz",
|
||||
@ -4478,75 +4530,75 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sentry-internal/browser-utils": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.28.0.tgz",
|
||||
"integrity": "sha512-SqntPnIXudP3FoKj4mQ1BVPC1RNzo4CGtAxJnLpbIUpdT/khJVM6Q59zrGl2MgZ7URZCI986L5jXihQeferf6g==",
|
||||
"version": "9.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.28.1.tgz",
|
||||
"integrity": "sha512-P/FEZkT7UqTw9P/2n/Y4Aa1OtGP6dnCvyqzPPkjiRdVa7Ep7S5ElBJloGv7077TLLBtAfCsEUVRlM1F6/jQoaA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "9.28.0"
|
||||
"@sentry/core": "9.28.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/feedback": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.28.0.tgz",
|
||||
"integrity": "sha512-z2jShmVENsesmDnShEOv841Saw0zXe1tX6GHNgkK9f6NrUMbL970JvGKByBFTffhQH6uQ0WeNPnXJ5L/YKnfDg==",
|
||||
"version": "9.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.28.1.tgz",
|
||||
"integrity": "sha512-HOk/c26D3nlClO/xEefev8fIJzRA621PFQvNFPu/y0Z5HujEqSmIsrff0cXszPPYD95h4Mwk63E0ZYdspdeXcw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "9.28.0"
|
||||
"@sentry/core": "9.28.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/replay": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.28.0.tgz",
|
||||
"integrity": "sha512-BVGVBlmcpJdT55d/vywjfK1u6zMC5ycjJBxU1wUCNgCU3cSKRDBnvmYgk/+Ay23bFryT28Q4hM1p5qBBAOfxjQ==",
|
||||
"version": "9.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.28.1.tgz",
|
||||
"integrity": "sha512-Tv9pkfAX+1bmhxF42TL0c4uTiK2+rp5LMYEPdz6JBfpfvG/Z1unPGsuB7fQmHYKyfHBQJmi92DZV+smljm7w/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/browser-utils": "9.28.0",
|
||||
"@sentry/core": "9.28.0"
|
||||
"@sentry-internal/browser-utils": "9.28.1",
|
||||
"@sentry/core": "9.28.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/replay-canvas": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.28.0.tgz",
|
||||
"integrity": "sha512-Bv4mbtUrRV3p6PpFQPseLv3+Uaen+3AlfX02Z6QHY1sMa4lpt+U8OHfRGLprnzb6Rarw6fK2LNVL5rnV9LNMwA==",
|
||||
"version": "9.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.28.1.tgz",
|
||||
"integrity": "sha512-RtkogfcIpXLFCyV8CTnXmVTH2QauT/KwmUAXBbeOz3rRWsM19yjN1moHrsjxn7OdjTv+D4qWSCA8Ka1aKSpr7g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/replay": "9.28.0",
|
||||
"@sentry/core": "9.28.0"
|
||||
"@sentry-internal/replay": "9.28.1",
|
||||
"@sentry/core": "9.28.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.28.0.tgz",
|
||||
"integrity": "sha512-ttqiv3D9sIB43nZnJTTln1nXw1p4C5BDSh+sHmGUOiqdCH6ND3HByDITYMYIOz1lACSISTT4V+MEpqx0V25Tlw==",
|
||||
"version": "9.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.28.1.tgz",
|
||||
"integrity": "sha512-XAS46iQSq8lXTnv9udQP025JTf3PwSVRE9ePJVQhx25QBWxedqGhEOv5qqX9b1Ijf8KiZYXXhBWMQxBBXVzUaw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/browser-utils": "9.28.0",
|
||||
"@sentry-internal/feedback": "9.28.0",
|
||||
"@sentry-internal/replay": "9.28.0",
|
||||
"@sentry-internal/replay-canvas": "9.28.0",
|
||||
"@sentry/core": "9.28.0"
|
||||
"@sentry-internal/browser-utils": "9.28.1",
|
||||
"@sentry-internal/feedback": "9.28.1",
|
||||
"@sentry-internal/replay": "9.28.1",
|
||||
"@sentry-internal/replay-canvas": "9.28.1",
|
||||
"@sentry/core": "9.28.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.28.0.tgz",
|
||||
"integrity": "sha512-vzD9xhg9S864jxfCpq77feCE4y7iP2cZYsNMoTupl1vTUlmXlhp7XgF832fEMjEZq4vrPhaqCNsde7Sc3PAbaQ==",
|
||||
"version": "9.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.28.1.tgz",
|
||||
"integrity": "sha512-6q59r/71MeE+4StkvwdKAAyhBBNpWcii0HeiWBZ3l1gaFYQlb6bChjZJRZmxSzF5dnvkdF4duQbAC3JmjeIbPA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@ -4717,15 +4769,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@spotlightjs/overlay": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@spotlightjs/overlay/-/overlay-2.15.1.tgz",
|
||||
"integrity": "sha512-5TpHWFRiTm8rrNINOQs9iFsqVnguFGHU1cK/bmhrysNzts4tYQT9d+kWvl++GlItKezIPbu5xPD9VoapO30cyw==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@spotlightjs/overlay/-/overlay-3.0.0.tgz",
|
||||
"integrity": "sha512-0b03WtsykqpcOKmjDRnRZf0GGfaEB6ZHGctLZZxFK4NHTDBNJ6BaQZjunr4XU35kKR5BT2OFp5E/DPKluih0Hg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@spotlightjs/sidecar": {
|
||||
"version": "1.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@spotlightjs/sidecar/-/sidecar-1.11.3.tgz",
|
||||
"integrity": "sha512-2FNZjnvJH71pAsYlJA/LIaEZ0jdtjqrlD58F/xJ5ZhI7z6US5zIqE7DMrqaK/tvObFam71CyCncKHRG6M0l6Cg==",
|
||||
"version": "1.11.4",
|
||||
"resolved": "https://registry.npmjs.org/@spotlightjs/sidecar/-/sidecar-1.11.4.tgz",
|
||||
"integrity": "sha512-8uDJNhvt6uVNvIoBltjRBqb0a//SxkKoyPACtNjq9k9qMYSfFhE0RVtgqnJNBineXeJfxzK5uvzeG/X7pEhYeQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
@ -4741,21 +4793,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@spotlightjs/spotlight": {
|
||||
"version": "2.13.3",
|
||||
"resolved": "https://registry.npmjs.org/@spotlightjs/spotlight/-/spotlight-2.13.3.tgz",
|
||||
"integrity": "sha512-wDnXJaSVexPC/+blgXXx2AYCk7S+5lT4TCJmu0HZAVtYd2sDgNub/wAOitsKYxvpRtIQnPe55IlvL4r1X7goSg==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@spotlightjs/spotlight/-/spotlight-3.0.0.tgz",
|
||||
"integrity": "sha512-dkMineYpONLUmkHh7gvBhjf34ES8a08KDQXNem9/0JzAMy/bXSDlC95sqkX9wDfKWjq2rJKYjJulNtCuGHDaeA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@sentry/node": "^8.49.0",
|
||||
"@spotlightjs/overlay": "2.15.1",
|
||||
"@spotlightjs/sidecar": "1.11.3",
|
||||
"@spotlightjs/overlay": "3.0.0",
|
||||
"@spotlightjs/sidecar": "1.11.4",
|
||||
"import-meta-resolve": "^4.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"spotlight": "bin/run.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
@ -16940,6 +16992,12 @@
|
||||
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/hotkeys-js": {
|
||||
"version": "3.8.7",
|
||||
"resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.8.7.tgz",
|
||||
"integrity": "sha512-ckAx3EkUr5XjDwjEHDorHxRO2Kb7z6Z2Sxul4MbBkN8Nho7XDslQsgMJT+CiJ5Z4TgRxxvKHEpuLE3imzqy4Lg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/html-escaper": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||
@ -17143,9 +17201,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/import-in-the-middle": {
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.13.2.tgz",
|
||||
"integrity": "sha512-Yjp9X7s2eHSXvZYQ0aye6UvwYPrVB5C2k47fuXjFKnYinAByaDZjh4t9MT2wEga9775n6WaIqyHnQhBxYtX2mg==",
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.14.0.tgz",
|
||||
"integrity": "sha512-g5zLT0HaztRJWysayWYiUq/7E5H825QIiecMD2pI5QO7Wzr847l6GDvPvmZaDIdrDtS2w7qRczywxiK6SL5vRw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"acorn": "^8.14.0",
|
||||
@ -21632,6 +21690,57 @@
|
||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ninja-keys": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ninja-keys/-/ninja-keys-1.2.2.tgz",
|
||||
"integrity": "sha512-ylo8jzKowi3XBHkgHRjBJaKQkl32WRLr7kRiA0ajiku11vHRDJ2xANtTScR5C7XlDwKEOYvUPesCKacUeeLAYw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@material/mwc-icon": "0.25.3",
|
||||
"hotkeys-js": "3.8.7",
|
||||
"lit": "2.2.6"
|
||||
}
|
||||
},
|
||||
"node_modules/ninja-keys/node_modules/@lit/reactive-element": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz",
|
||||
"integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@lit-labs/ssr-dom-shim": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ninja-keys/node_modules/lit": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/lit/-/lit-2.2.6.tgz",
|
||||
"integrity": "sha512-K2vkeGABfSJSfkhqHy86ujchJs3NR9nW1bEEiV+bXDkbiQ60Tv5GUausYN2mXigZn8lC1qXuc46ArQRKYmumZw==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@lit/reactive-element": "^1.3.0",
|
||||
"lit-element": "^3.2.0",
|
||||
"lit-html": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ninja-keys/node_modules/lit-element": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.3.3.tgz",
|
||||
"integrity": "sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@lit-labs/ssr-dom-shim": "^1.1.0",
|
||||
"@lit/reactive-element": "^1.3.0",
|
||||
"lit-html": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ninja-keys/node_modules/lit-html": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.8.0.tgz",
|
||||
"integrity": "sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@types/trusted-types": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abort-controller": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz",
|
||||
|
@ -102,8 +102,8 @@
|
||||
"@open-wc/lit-helpers": "^0.7.0",
|
||||
"@patternfly/elements": "^4.1.0",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@sentry/browser": "^9.28.0",
|
||||
"@spotlightjs/spotlight": "^2.13.3",
|
||||
"@sentry/browser": "^9.28.1",
|
||||
"@spotlightjs/spotlight": "^3.0.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"change-case": "^5.4.4",
|
||||
@ -122,6 +122,7 @@
|
||||
"lit": "^3.2.0",
|
||||
"md-front-matter": "^1.0.4",
|
||||
"mermaid": "^11.6.0",
|
||||
"ninja-keys": "^1.2.2",
|
||||
"rapidoc": "^9.3.8",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
|
172
web/src/admin/AdminInterface/AdminCommands.ts
Normal file
172
web/src/admin/AdminInterface/AdminCommands.ts
Normal file
@ -0,0 +1,172 @@
|
||||
import { navigate } from "@goauthentik/elements/router/RouterOutlet";
|
||||
import { INinjaAction } from "ninja-keys/dist/interfaces/ininja-action.js";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
|
||||
export const adminCommands: INinjaAction[] = [
|
||||
{
|
||||
id: msg("Overview"),
|
||||
title: msg("Dashboard"),
|
||||
handler: () => navigate("/administration/overview"),
|
||||
section: msg("Dashboards"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/administration/dashboard/users"),
|
||||
id: msg("User Statistics"),
|
||||
title: msg("User Statistics"),
|
||||
icon: '<i class="pf-icon pf-icon-user"></i>',
|
||||
section: msg("Dashboards"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/administration/system-tasks"),
|
||||
id: msg("System Tasks"),
|
||||
title: msg("System Tasks"),
|
||||
section: msg("Dashboards"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/core/applications"),
|
||||
id: msg("Applications"),
|
||||
title: msg("Applications"),
|
||||
section: msg("Applications"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/core/providers"),
|
||||
id: msg("Providers"),
|
||||
title: msg("Providers"),
|
||||
section: msg("Applications"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/outpost/outposts"),
|
||||
id: msg("Outposts"),
|
||||
title: msg("Outposts"),
|
||||
section: msg("Applications"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/events/log"),
|
||||
id: msg("Logs"),
|
||||
title: msg("Logs"),
|
||||
section: msg("Events"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/events/rules"),
|
||||
id: msg("Notification Rules"),
|
||||
title: msg("Notification Rules"),
|
||||
section: msg("Events"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/events/transports"),
|
||||
id: msg("Notification Transports"),
|
||||
title: msg("Notification Transports"),
|
||||
section: msg("Events"),
|
||||
},
|
||||
|
||||
{
|
||||
handler: () => navigate("/policy/policies"),
|
||||
id: msg("Policies"),
|
||||
title: msg("Policies"),
|
||||
section: msg("Customization"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/core/property-mappings"),
|
||||
id: msg("Property Mappings"),
|
||||
title: msg("Property Mappings"),
|
||||
section: msg("Customization"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/blueprints/instances"),
|
||||
id: msg("Blueprints"),
|
||||
title: msg("Blueprints"),
|
||||
section: msg("Customization"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/policy/reputation"),
|
||||
id: msg("Reputation scores"),
|
||||
title: msg("Reputation scores"),
|
||||
section: msg("Customization"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/flow/flows"),
|
||||
id: msg("Flows"),
|
||||
title: msg("Flows"),
|
||||
section: msg("Flows"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/flow/stages"),
|
||||
id: msg("Stages"),
|
||||
title: msg("Stages"),
|
||||
section: msg("Flows"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/flow/stages/prompts"),
|
||||
id: msg("Prompts"),
|
||||
title: msg("Prompts"),
|
||||
section: msg("Flows"),
|
||||
},
|
||||
|
||||
{
|
||||
handler: () => navigate("/identity/users"),
|
||||
id: msg("Users"),
|
||||
title: msg("Users"),
|
||||
section: msg("Directory"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/identity/groups"),
|
||||
id: msg("Groups"),
|
||||
title: msg("Groups"),
|
||||
section: msg("Directory"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/identity/roles"),
|
||||
id: msg("Roles"),
|
||||
title: msg("Roles"),
|
||||
section: msg("Directory"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/core/sources"),
|
||||
id: msg("Federation and Social login"),
|
||||
title: msg("Federation and Social login"),
|
||||
section: msg("Directory"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/core/tokens"),
|
||||
id: msg("Tokens and App passwords"),
|
||||
title: msg("Tokens and App passwords"),
|
||||
section: msg("Directory"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/flow/stages/invitations"),
|
||||
id: msg("Invitations"),
|
||||
title: msg("Invitations"),
|
||||
section: msg("Directory"),
|
||||
},
|
||||
|
||||
{
|
||||
handler: () => navigate("/core/brands"),
|
||||
id: msg("Brands"),
|
||||
title: msg("Brands"),
|
||||
section: msg("System"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/crypto/certificates"),
|
||||
id: msg("Certificates"),
|
||||
title: msg("Certificates"),
|
||||
section: msg("System"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/outpost/integrations"),
|
||||
id: msg("Outpost Integrations"),
|
||||
title: msg("Outpost Integrations"),
|
||||
section: msg("System"),
|
||||
},
|
||||
{
|
||||
handler: () => navigate("/admin/settings"),
|
||||
id: msg("Settings"),
|
||||
title: msg("Settings"),
|
||||
section: msg("System"),
|
||||
},
|
||||
{
|
||||
handler: () => window.location.assign("/if/user/"),
|
||||
id: msg("User interface"),
|
||||
title: msg("Go to my User page"),
|
||||
},
|
||||
];
|
@ -1,5 +1,6 @@
|
||||
import "#admin/AdminInterface/AboutModal";
|
||||
import type { AboutModal } from "#admin/AdminInterface/AboutModal";
|
||||
import { adminCommands } from "#admin/AdminInterface/AdminCommands";
|
||||
import { ROUTES } from "#admin/Routes";
|
||||
import { EVENT_API_DRAWER_TOGGLE, EVENT_NOTIFICATION_DRAWER_TOGGLE } from "#common/constants";
|
||||
import { configureSentry } from "#common/sentry/index";
|
||||
@ -21,6 +22,7 @@ import { getURLParam, updateURLParams } from "#elements/router/RouteMatch";
|
||||
import "#elements/router/RouterOutlet";
|
||||
import "#elements/sidebar/Sidebar";
|
||||
import "#elements/sidebar/SidebarItem";
|
||||
import "ninja-keys";
|
||||
|
||||
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
|
||||
import { customElement, eventOptions, property, query } from "lit/decorators.js";
|
||||
@ -119,6 +121,10 @@ export class AdminInterface extends WithCapabilitiesConfig(AuthenticatedInterfac
|
||||
.pf-c-drawer__panel {
|
||||
z-index: var(--pf-global--ZIndex--xl);
|
||||
}
|
||||
ninja-keys {
|
||||
--ninja-z-index: 99999;
|
||||
--ninja-accent-color: var(--ak-accent);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@ -190,6 +196,11 @@ export class AdminInterface extends WithCapabilitiesConfig(AuthenticatedInterfac
|
||||
};
|
||||
|
||||
return html` <ak-locale-context>
|
||||
<ninja-keys
|
||||
.data=${adminCommands}
|
||||
noAutoLoadMdicons
|
||||
class="${this.activeTheme === UiThemeEnum.Dark ? "dark" : ""}"
|
||||
></ninja-keys>
|
||||
<div class="pf-c-page">
|
||||
<ak-page-navbar ?open=${this.sidebarOpen} @sidebar-toggle=${this.sidebarListener}>
|
||||
<ak-version-banner></ak-version-banner>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-private-textarea-input.js";
|
||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
@ -46,7 +46,7 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-private-textarea-input
|
||||
<ak-secret-textarea-input
|
||||
label=${msg("Certificate")}
|
||||
name="certificateData"
|
||||
input-hint="code"
|
||||
@ -54,8 +54,8 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
||||
required
|
||||
?revealed=${this.instance === undefined}
|
||||
help=${msg("PEM-encoded Certificate data.")}
|
||||
></ak-private-textarea-input>
|
||||
<ak-private-textarea-input
|
||||
></ak-secret-textarea-input>
|
||||
<ak-secret-textarea-input
|
||||
label=${msg("Private Key")}
|
||||
name="keyData"
|
||||
input-hint="code"
|
||||
@ -63,7 +63,7 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
||||
help=${msg(
|
||||
"Optional Private Key. If this is set, you can use this keypair for encryption.",
|
||||
)}
|
||||
></ak-private-textarea-input>`;
|
||||
></ak-secret-textarea-input>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_REFRESH_ENTERPRISE } from "@goauthentik/common/constants";
|
||||
import "@goauthentik/components/ak-private-textarea-input.js";
|
||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
@ -62,13 +62,13 @@ export class EnterpriseLicenseForm extends ModelForm<License, string> {
|
||||
value="${ifDefined(this.installID)}"
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-private-textarea-input
|
||||
<ak-secret-textarea-input
|
||||
name="key"
|
||||
?revealed=${this.instance === undefined}
|
||||
label=${msg("License key")}
|
||||
input-hint="code"
|
||||
>
|
||||
</ak-private-textarea-input>`;
|
||||
</ak-secret-textarea-input>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,8 @@ import {
|
||||
UserMatchingModeToLabel,
|
||||
} from "@goauthentik/admin/sources/oauth/utils";
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-private-text-input.js";
|
||||
import "@goauthentik/components/ak-private-textarea-input.js";
|
||||
import "@goauthentik/components/ak-secret-text-input.js";
|
||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
||||
import "@goauthentik/components/ak-switch-input";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
import "@goauthentik/components/ak-textarea-input";
|
||||
@ -248,22 +248,22 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
||||
value=${ifDefined(this.instance?.syncPrincipal)}
|
||||
help=${msg("Principal used to authenticate to the KDC for syncing.")}
|
||||
></ak-text-input>
|
||||
<ak-private-text-input
|
||||
<ak-secret-text-input
|
||||
name="syncPassword"
|
||||
label=${msg("Sync password")}
|
||||
?revealed=${this.instance === undefined}
|
||||
help=${msg(
|
||||
"Password used to authenticate to the KDC for syncing. Optional if Sync keytab or Sync credentials cache is provided.",
|
||||
)}
|
||||
></ak-private-text-input>
|
||||
<ak-private-textarea-input
|
||||
></ak-secret-text-input>
|
||||
<ak-secret-textarea-input
|
||||
name="syncKeytab"
|
||||
label=${msg("Sync keytab")}
|
||||
?revealed=${this.instance === undefined}
|
||||
help=${msg(
|
||||
"Keytab used to authenticate to the KDC for syncing. Optional if Sync password or Sync credentials cache is provided. Must be base64 encoded or in the form TYPE:residual.",
|
||||
)}
|
||||
></ak-private-textarea-input>
|
||||
></ak-secret-textarea-input>
|
||||
<ak-text-input
|
||||
name="syncCcache"
|
||||
label=${msg("Sync credentials cache")}
|
||||
@ -285,14 +285,14 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
||||
"Force the use of a specific server name for SPNEGO. Must be in the form HTTP@domain",
|
||||
)}
|
||||
></ak-text-input>
|
||||
<ak-private-textarea-input
|
||||
<ak-secret-textarea-input
|
||||
name="spnegoKeytab"
|
||||
label=${msg("SPNEGO keytab")}
|
||||
?revealed=${this.instance === undefined}
|
||||
help=${msg(
|
||||
"Keytab used for SPNEGO. Optional if SPNEGO credentials cache is provided. Must be base64 encoded or in the form TYPE:residual.",
|
||||
)}
|
||||
></ak-private-textarea-input>
|
||||
></ak-secret-textarea-input>
|
||||
<ak-text-input
|
||||
name="spnegoCcache"
|
||||
label=${msg("SPNEGO credentials cache")}
|
||||
|
@ -2,7 +2,7 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search";
|
||||
import { placeholderHelperText } from "@goauthentik/admin/helperText";
|
||||
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-private-text-input.js";
|
||||
import "@goauthentik/components/ak-secret-text-input.js";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
@ -260,11 +260,11 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
||||
class="pf-c-form-control"
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-private-text-input
|
||||
<ak-secret-text-input
|
||||
label=${msg("Bind Password")}
|
||||
name="bindPassword"
|
||||
?revealed=${this.instance === undefined}
|
||||
></ak-private-text-input>
|
||||
></ak-secret-text-input>
|
||||
<ak-form-element-horizontal label=${msg("Base DN")} required name="baseDn">
|
||||
<input
|
||||
type="text"
|
||||
|
@ -8,8 +8,8 @@ import {
|
||||
UserMatchingModeToLabel,
|
||||
} from "@goauthentik/admin/sources/oauth/utils";
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-private-textarea-input.js";
|
||||
import "@goauthentik/components/ak-radio-input";
|
||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
@ -441,14 +441,14 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">${msg("Also known as Client ID.")}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-private-textarea-input
|
||||
<ak-secret-textarea-input
|
||||
label=${msg("Consumer secret")}
|
||||
name="consumerSecret"
|
||||
input-hint="code"
|
||||
help=${msg("Also known as Client Secret.")}
|
||||
required
|
||||
?revealed=${this.instance === undefined}
|
||||
></ak-private-textarea-input>
|
||||
></ak-secret-textarea-input>
|
||||
<ak-form-element-horizontal label=${msg("Scopes")} name="additionalScopes">
|
||||
<input
|
||||
type="text"
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { RenderFlowOption } from "@goauthentik/admin/flows/utils";
|
||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-private-text-input.js";
|
||||
import "@goauthentik/components/ak-secret-text-input.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
@ -95,13 +95,13 @@ export class AuthenticatorDuoStageForm extends BaseStageForm<AuthenticatorDuoSta
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-private-text-input
|
||||
<ak-secret-text-input
|
||||
name="clientSecret"
|
||||
label=${msg("Secret key")}
|
||||
input-hint="code"
|
||||
required
|
||||
?revealed=${this.instance === undefined}
|
||||
></ak-private-text-input>
|
||||
></ak-secret-text-input>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group>
|
||||
@ -125,12 +125,12 @@ export class AuthenticatorDuoStageForm extends BaseStageForm<AuthenticatorDuoSta
|
||||
spellcheck="false"
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-private-text-input
|
||||
<ak-secret-text-input
|
||||
name="adminSecretKey"
|
||||
label=${msg("Secret key")}
|
||||
input-hint="code"
|
||||
?revealed=${this.instance === undefined}
|
||||
></ak-private-text-input>
|
||||
></ak-secret-text-input>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group expanded>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { RenderFlowOption } from "@goauthentik/admin/flows/utils";
|
||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-private-text-input.js";
|
||||
import "@goauthentik/components/ak-secret-text-input.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
@ -77,11 +77,11 @@ export class AuthenticatorEmailStageForm extends BaseStageForm<AuthenticatorEmai
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-private-text-input
|
||||
<ak-secret-text-input
|
||||
name="password"
|
||||
label=${msg("SMTP Password")}
|
||||
?revealed=${this.instance === undefined}
|
||||
></ak-private-text-input>
|
||||
></ak-secret-text-input>
|
||||
|
||||
<ak-form-element-horizontal name="useTls">
|
||||
<label class="pf-c-switch">
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-number-input";
|
||||
import "@goauthentik/components/ak-private-text-input.js";
|
||||
import "@goauthentik/components/ak-secret-text-input.js";
|
||||
import "@goauthentik/components/ak-switch-input";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
@ -70,7 +70,7 @@ export class CaptchaStageForm extends BaseStageForm<CaptchaStage> {
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-private-text-input
|
||||
<ak-secret-text-input
|
||||
name="privateKey"
|
||||
label=${msg("Private Key")}
|
||||
input-hint="code"
|
||||
@ -79,7 +79,7 @@ export class CaptchaStageForm extends BaseStageForm<CaptchaStage> {
|
||||
help=${msg(
|
||||
"Private key, acquired from https://www.google.com/recaptcha/intro/v3.html.",
|
||||
)}
|
||||
></ak-private-text-input>
|
||||
></ak-secret-text-input>
|
||||
|
||||
<ak-switch-input
|
||||
name="interactive"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-private-text-input.js";
|
||||
import "@goauthentik/components/ak-secret-text-input.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
||||
@ -73,11 +73,11 @@ export class EmailStageForm extends BaseStageForm<EmailStage> {
|
||||
class="pf-c-form-control"
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-private-text-input
|
||||
<ak-secret-text-input
|
||||
label=${msg("SMTP Password")}
|
||||
name="password"
|
||||
?revealed=${this.instance === undefined}
|
||||
></ak-private-text-input>
|
||||
></ak-secret-text-input>
|
||||
<ak-form-element-horizontal name="useTls">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { AKElement, type AKElementProps } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement.js";
|
||||
|
||||
import { TemplateResult, html, nothing } from "lit";
|
||||
@ -6,6 +6,19 @@ import { property } from "lit/decorators.js";
|
||||
|
||||
type HelpType = TemplateResult | typeof nothing;
|
||||
|
||||
export interface HorizontalLightComponentProps<T> extends AKElementProps {
|
||||
name: string;
|
||||
label?: string;
|
||||
required?: boolean;
|
||||
help?: string;
|
||||
bighelp?: TemplateResult | TemplateResult[];
|
||||
hidden?: boolean;
|
||||
invalid?: boolean;
|
||||
errorMessages?: string[];
|
||||
value?: T;
|
||||
inputHint?: string;
|
||||
}
|
||||
|
||||
export class HorizontalLightComponent<T> extends AKElement {
|
||||
// Render into the lightDOM. This effectively erases the shadowDOM nature of this component, but
|
||||
// we're not actually using that and, for the meantime, we need the form handlers to be able to
|
||||
@ -18,37 +31,81 @@ export class HorizontalLightComponent<T> extends AKElement {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name attribute for the form element
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String, reflect: true })
|
||||
name!: string;
|
||||
|
||||
/**
|
||||
* The label for the input control
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String, reflect: true })
|
||||
label = "";
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
required = false;
|
||||
|
||||
/**
|
||||
* Help text to display below the form element. Optional
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String, reflect: true })
|
||||
help = "";
|
||||
|
||||
/**
|
||||
* Extended help content. Optional. Expects to be a TemplateResult
|
||||
* @property
|
||||
*/
|
||||
@property({ type: Object })
|
||||
bighelp?: TemplateResult | TemplateResult[];
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
hidden = false;
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
invalid = false;
|
||||
|
||||
/**
|
||||
* @property
|
||||
*/
|
||||
@property({ attribute: false })
|
||||
errorMessages: string[] = [];
|
||||
|
||||
/**
|
||||
* @attribute
|
||||
* @property
|
||||
*/
|
||||
@property({ attribute: false })
|
||||
value?: T;
|
||||
|
||||
/**
|
||||
* Input hint.
|
||||
* - `code`: uses a monospace font and disables spellcheck & autocomplete
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String, attribute: "input-hint" })
|
||||
inputHint = "";
|
||||
|
||||
renderControl() {
|
||||
protected renderControl() {
|
||||
throw new Error("Must be implemented in a subclass");
|
||||
}
|
||||
|
||||
|
159
web/src/components/ak-hidden-text-input.ts
Normal file
159
web/src/components/ak-hidden-text-input.ts
Normal file
@ -0,0 +1,159 @@
|
||||
import { bound } from "#elements/decorators/bound";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { css, html } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators.js";
|
||||
import { classMap } from "lit/directives/class-map.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import {
|
||||
HorizontalLightComponent,
|
||||
HorizontalLightComponentProps,
|
||||
} from "./HorizontalLightComponent";
|
||||
import "./ak-visibility-toggle.js";
|
||||
import type { VisibilityToggleProps } from "./ak-visibility-toggle.js";
|
||||
|
||||
type BaseProps = HorizontalLightComponentProps<string> &
|
||||
Pick<VisibilityToggleProps, "showMessage" | "hideMessage">;
|
||||
|
||||
export interface AkHiddenTextInputProps extends BaseProps {
|
||||
revealed: boolean;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export type InputLike = HTMLTextAreaElement | HTMLInputElement;
|
||||
|
||||
/**
|
||||
* @element ak-hidden-text-input
|
||||
* @class AkHiddenTextInput
|
||||
*
|
||||
* A text-input field with a visibility control, so you can show/hide sensitive fields.
|
||||
*
|
||||
* ## CSS Parts
|
||||
* @csspart container - The main container div
|
||||
* @csspart input - The input element
|
||||
* @csspart toggle - The visibility toggle button
|
||||
*
|
||||
*/
|
||||
@customElement("ak-hidden-text-input")
|
||||
export class AkHiddenTextInput<T extends InputLike = HTMLInputElement>
|
||||
extends HorizontalLightComponent<string>
|
||||
implements AkHiddenTextInputProps
|
||||
{
|
||||
public static get styles() {
|
||||
return [
|
||||
css`
|
||||
main {
|
||||
display: flex;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String, reflect: true })
|
||||
public value = "";
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public revealed = false;
|
||||
|
||||
/**
|
||||
* Text for when the input has no set value
|
||||
*
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String })
|
||||
public placeholder?: string;
|
||||
|
||||
/**
|
||||
* Specify kind of help the browser should try to provide
|
||||
*
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String })
|
||||
public autocomplete?: "none" | AutoFill;
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String, attribute: "show-message" })
|
||||
public showMessage = msg("Show field content");
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String, attribute: "hide-message" })
|
||||
public hideMessage = msg("Hide field content");
|
||||
|
||||
@query("#main > input")
|
||||
protected inputField!: T;
|
||||
|
||||
@bound
|
||||
private handleToggleVisibility() {
|
||||
this.revealed = !this.revealed;
|
||||
|
||||
// Maintain focus on input after toggle
|
||||
this.updateComplete.then(() => {
|
||||
if (this.inputField && document.activeElement === this) {
|
||||
this.inputField.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Because of the peculiarities of how HorizontalLightComponent works, keeping its content
|
||||
// in the LightDom so the inner components actually inherit styling, the normal `css` options
|
||||
// aren't available. Embedding styles is bad styling, and we'll fix it in the next style
|
||||
// refresh.
|
||||
protected renderInputField(setValue: (ev: InputEvent) => void, code: boolean) {
|
||||
return html` <input
|
||||
style="flex: 1 1 auto; min-width: 0;"
|
||||
part="input"
|
||||
type=${this.revealed ? "text" : "password"}
|
||||
@input=${setValue}
|
||||
value=${ifDefined(this.value)}
|
||||
placeholder=${ifDefined(this.placeholder)}
|
||||
class="${classMap({
|
||||
"pf-c-form-control": true,
|
||||
"pf-m-monospace": code,
|
||||
})}"
|
||||
spellcheck=${code ? "false" : "true"}
|
||||
?required=${this.required}
|
||||
/>`;
|
||||
}
|
||||
|
||||
protected override renderControl() {
|
||||
const code = this.inputHint === "code";
|
||||
const setValue = (ev: InputEvent) => {
|
||||
this.value = (ev.target as T).value;
|
||||
};
|
||||
return html` <div style="display: flex; gap: 0.25rem">
|
||||
${this.renderInputField(setValue, code)}
|
||||
<!-- -->
|
||||
<ak-visibility-toggle
|
||||
part="toggle"
|
||||
style="flex: 0 0 auto; align-self: flex-start"
|
||||
?open=${this.revealed}
|
||||
show-message=${this.showMessage}
|
||||
hide-message=${this.hideMessage}
|
||||
@click=${() => (this.revealed = !this.revealed)}
|
||||
></ak-visibility-toggle>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ak-hidden-text-input": AkHiddenTextInput;
|
||||
}
|
||||
}
|
128
web/src/components/ak-hidden-textarea-input.ts
Normal file
128
web/src/components/ak-hidden-textarea-input.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import { css, html } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators.js";
|
||||
import { classMap } from "lit/directives/class-map.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { AkHiddenTextInput, type AkHiddenTextInputProps } from "./ak-hidden-text-input.js";
|
||||
|
||||
export interface AkHiddenTextAreaInputProps extends AkHiddenTextInputProps {
|
||||
/**
|
||||
* Number of visible text lines (rows)
|
||||
*/
|
||||
rows?: number;
|
||||
|
||||
/**
|
||||
* Number of visible character width (cols)
|
||||
*/
|
||||
cols?: number;
|
||||
|
||||
/**
|
||||
* How the textarea can be resized
|
||||
*/
|
||||
resize?: "none" | "both" | "horizontal" | "vertical";
|
||||
|
||||
/**
|
||||
* Whether text should wrap
|
||||
*/
|
||||
wrap?: "soft" | "hard" | "off";
|
||||
}
|
||||
|
||||
/**
|
||||
* @element ak-hidden-text-input
|
||||
* @class AkHiddenTextInput
|
||||
*
|
||||
* A text-input field with a visibility control, so you can show/hide sensitive fields.
|
||||
*
|
||||
* ## CSS Parts
|
||||
* @csspart container - The main container div
|
||||
* @csspart input - The input element
|
||||
* @csspart toggle - The visibility toggle button
|
||||
*
|
||||
*/
|
||||
@customElement("ak-hidden-textarea-input")
|
||||
export class AkHiddenTextAreaInput
|
||||
extends AkHiddenTextInput<HTMLTextAreaElement>
|
||||
implements AkHiddenTextAreaInputProps
|
||||
{
|
||||
/* These are mostly just forwarded to the textarea component. */
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: Number })
|
||||
rows?: number = 4;
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: Number })
|
||||
cols?: number;
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*
|
||||
* You want `resize=true` so that the resize value is visible in the component tag, activating
|
||||
* the CSS associated with these values.
|
||||
*/
|
||||
@property({ type: String, reflect: true })
|
||||
resize?: "none" | "both" | "horizontal" | "vertical" = "vertical";
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String })
|
||||
wrap?: "soft" | "hard" | "off" = "soft";
|
||||
|
||||
@query("#main > textarea")
|
||||
protected inputField!: HTMLTextAreaElement;
|
||||
|
||||
get displayValue() {
|
||||
const value = this.value ?? "";
|
||||
if (this.revealed) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return value
|
||||
.split("\n")
|
||||
.reduce((acc: string[], line: string) => [...acc, "*".repeat(line.length)], [])
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
// TODO: Because of the peculiarities of how HorizontalLightComponent works, keeping its content
|
||||
// in the LightDom so the inner components actually inherit styling, the normal `css` options
|
||||
// aren't available. Embedding styles is bad styling, and we'll fix it in the next style
|
||||
// refresh.
|
||||
protected override renderInputField(setValue: (ev: InputEvent) => void, code: boolean) {
|
||||
const wrap = this.revealed ? this.wrap : "soft";
|
||||
|
||||
return html`
|
||||
<textarea
|
||||
style="flex: 1 1 auto; min-width: 0;"
|
||||
part="textarea"
|
||||
@input=${setValue}
|
||||
placeholder=${ifDefined(this.placeholder)}
|
||||
rows=${ifDefined(this.rows)}
|
||||
cols=${ifDefined(this.cols)}
|
||||
wrap=${ifDefined(wrap)}
|
||||
class=${classMap({
|
||||
"pf-c-form-control": true,
|
||||
"pf-m-monospace": code,
|
||||
})}
|
||||
spellcheck=${code ? "false" : "true"}
|
||||
?required=${this.required}
|
||||
>
|
||||
${this.displayValue}</textarea
|
||||
>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ak-hidden-textarea-input": AkHiddenTextAreaInput;
|
||||
}
|
||||
}
|
@ -8,8 +8,8 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { HorizontalLightComponent } from "./HorizontalLightComponent";
|
||||
|
||||
@customElement("ak-private-text-input")
|
||||
export class AkPrivateTextInput extends HorizontalLightComponent<string> {
|
||||
@customElement("ak-secret-text-input")
|
||||
export class AkSecretTextInput extends HorizontalLightComponent<string> {
|
||||
@property({ type: String, reflect: true })
|
||||
public value = "";
|
||||
|
||||
@ -23,7 +23,7 @@ export class AkPrivateTextInput extends HorizontalLightComponent<string> {
|
||||
this.revealed = true;
|
||||
}
|
||||
|
||||
#renderPrivateInput() {
|
||||
#renderSecretInput() {
|
||||
return html`<div class="pf-c-form__horizontal-group" @click=${() => this.#onReveal()}>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
@ -60,14 +60,14 @@ export class AkPrivateTextInput extends HorizontalLightComponent<string> {
|
||||
}
|
||||
|
||||
public override renderControl() {
|
||||
return this.revealed ? this.renderVisibleInput() : this.#renderPrivateInput();
|
||||
return this.revealed ? this.renderVisibleInput() : this.#renderSecretInput();
|
||||
}
|
||||
}
|
||||
|
||||
export default AkPrivateTextInput;
|
||||
export default AkSecretTextInput;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ak-private-text-input": AkPrivateTextInput;
|
||||
"ak-secret-text-input": AkSecretTextInput;
|
||||
}
|
||||
}
|
@ -5,10 +5,10 @@ import { customElement, property } from "lit/decorators.js";
|
||||
import { classMap } from "lit/directives/class-map.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { AkPrivateTextInput } from "./ak-private-text-input.js";
|
||||
import { AkSecretTextInput } from "./ak-secret-text-input.js";
|
||||
|
||||
@customElement("ak-private-textarea-input")
|
||||
export class AkPrivateTextAreaInput extends AkPrivateTextInput {
|
||||
@customElement("ak-secret-textarea-input")
|
||||
export class AkSecretTextAreaInput extends AkSecretTextInput {
|
||||
protected override renderVisibleInput() {
|
||||
const code = this.inputHint === "code";
|
||||
const setValue = (ev: InputEvent) => {
|
||||
@ -34,10 +34,10 @@ export class AkPrivateTextAreaInput extends AkPrivateTextInput {
|
||||
}
|
||||
}
|
||||
|
||||
export default AkPrivateTextAreaInput;
|
||||
export default AkSecretTextAreaInput;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ak-private-textarea-input": AkPrivateTextAreaInput;
|
||||
"ak-secret-textarea-input": AkSecretTextAreaInput;
|
||||
}
|
||||
}
|
89
web/src/components/ak-visibility-toggle.ts
Normal file
89
web/src/components/ak-visibility-toggle.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { AKElement } from "@goauthentik/elements/Base.js";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
export interface VisibilityToggleProps {
|
||||
open: boolean;
|
||||
disabled: boolean;
|
||||
showMessage: string;
|
||||
hideMessage: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @component ak-visibility-toggle
|
||||
* @class VisibilityToggle
|
||||
*
|
||||
* A straightforward two-state iconic button we use in a few places as way of telling users to hide
|
||||
* or show something secret, such as a password or private key. Expects the client to manage its
|
||||
* state.
|
||||
*
|
||||
* @events
|
||||
* - click: when the toggle is clicked.
|
||||
*/
|
||||
@customElement("ak-visibility-toggle")
|
||||
export class VisibilityToggle extends AKElement implements VisibilityToggleProps {
|
||||
static get styles() {
|
||||
return [PFBase, PFButton];
|
||||
}
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
open = false;
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
disabled = false;
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String, attribute: "show-message" })
|
||||
showMessage = msg("Show field content");
|
||||
|
||||
/**
|
||||
* @property
|
||||
* @attribute
|
||||
*/
|
||||
@property({ type: String, attribute: "hide-message" })
|
||||
hideMessage = msg("Hide field content");
|
||||
|
||||
render() {
|
||||
const [label, icon] = this.open
|
||||
? [this.hideMessage, "fa-eye"]
|
||||
: [this.showMessage, "fa-eye-slash"];
|
||||
|
||||
const onClick = (ev: PointerEvent) => {
|
||||
ev.stopPropagation();
|
||||
this.dispatchEvent(new PointerEvent(ev.type, ev));
|
||||
};
|
||||
|
||||
return html`<button
|
||||
aria-label=${label}
|
||||
title=${label}
|
||||
@click=${onClick}
|
||||
?disabled=${this.disabled}
|
||||
class="pf-c-button pf-m-control"
|
||||
type="button"
|
||||
>
|
||||
<i class="fas ${icon}" aria-hidden="true"></i>
|
||||
</button>`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ak-visibility-toggle": VisibilityToggle;
|
||||
}
|
||||
}
|
93
web/src/components/stories/ak-hidden-text-input.stories.ts
Normal file
93
web/src/components/stories/ak-hidden-text-input.stories.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import type { Meta, StoryObj } from "@storybook/web-components";
|
||||
|
||||
import { html, nothing } from "lit";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import "../ak-hidden-text-input";
|
||||
import { type AkHiddenTextInput, type AkHiddenTextInputProps } from "../ak-hidden-text-input.js";
|
||||
|
||||
const metadata: Meta<AkHiddenTextInputProps> = {
|
||||
title: "Components / <ak-hidden-text-input>",
|
||||
component: "ak-hidden-text-input",
|
||||
tags: ["autodocs"],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: `
|
||||
# Hidden Text Input Component
|
||||
|
||||
A text-input field with a visibility control, so you can show/hide sensitive fields.
|
||||
`,
|
||||
},
|
||||
},
|
||||
layout: "padded",
|
||||
},
|
||||
argTypes: {
|
||||
label: {
|
||||
control: "text",
|
||||
description: "Label text for the input field",
|
||||
},
|
||||
value: {
|
||||
control: "text",
|
||||
description: "Current value of the input",
|
||||
},
|
||||
revealed: {
|
||||
control: "boolean",
|
||||
description: "Whether the text is currently visible",
|
||||
},
|
||||
placeholder: {
|
||||
control: "text",
|
||||
description: "Placeholder text for the input",
|
||||
},
|
||||
required: {
|
||||
control: "boolean",
|
||||
description: "Whether the input is required",
|
||||
},
|
||||
inputHint: {
|
||||
control: "select",
|
||||
options: ["text", "code"],
|
||||
description: "Input type hint for styling and behavior",
|
||||
},
|
||||
showMessage: {
|
||||
control: "text",
|
||||
description: "Custom message for show action",
|
||||
},
|
||||
hideMessage: {
|
||||
control: "text",
|
||||
description: "Custom message for hide action",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default metadata;
|
||||
|
||||
type Story = StoryObj<AkHiddenTextInput>;
|
||||
|
||||
const Template: Story = {
|
||||
args: {
|
||||
label: "Hidden Text Input",
|
||||
value: "",
|
||||
revealed: false,
|
||||
},
|
||||
render: (args) => html`
|
||||
<ak-hidden-text-input
|
||||
label=${ifDefined(args.label)}
|
||||
value=${ifDefined(args.value)}
|
||||
?revealed=${args.revealed}
|
||||
placeholder=${ifDefined(args.placeholder)}
|
||||
?required=${args.required}
|
||||
input-hint=${ifDefined(args.inputHint)}
|
||||
show-message=${ifDefined(args.showMessage)}
|
||||
hide-message=${ifDefined(args.hideMessage)}
|
||||
></ak-hidden-text-input>
|
||||
`,
|
||||
};
|
||||
|
||||
export const Password: Story = {
|
||||
...Template,
|
||||
args: {
|
||||
label: "Password",
|
||||
placeholder: "Enter your password",
|
||||
required: true,
|
||||
},
|
||||
};
|
140
web/src/components/stories/ak-hidden-textarea-input.stories.ts
Normal file
140
web/src/components/stories/ak-hidden-textarea-input.stories.ts
Normal file
@ -0,0 +1,140 @@
|
||||
import type { Meta, StoryObj } from "@storybook/web-components";
|
||||
|
||||
import { html, nothing } from "lit";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import "../ak-hidden-textarea-input";
|
||||
import {
|
||||
type AkHiddenTextAreaInput,
|
||||
type AkHiddenTextAreaInputProps,
|
||||
} from "../ak-hidden-textarea-input.js";
|
||||
|
||||
const metadata: Meta<AkHiddenTextAreaInputProps> = {
|
||||
title: "Components / <ak-hidden-textarea-input>",
|
||||
component: "ak-hidden-textarea-input",
|
||||
tags: ["autodocs"],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: `
|
||||
# Hidden Textarea Input Component
|
||||
|
||||
A textarea input field with a visibility control, so you can show/hide sensitive fields.
|
||||
`,
|
||||
},
|
||||
},
|
||||
layout: "padded",
|
||||
},
|
||||
argTypes: {
|
||||
label: {
|
||||
control: "text",
|
||||
description: "Label text for the input field",
|
||||
},
|
||||
value: {
|
||||
control: "text",
|
||||
description: "Current value of the input",
|
||||
},
|
||||
revealed: {
|
||||
control: "boolean",
|
||||
description: "Whether the text is currently visible",
|
||||
},
|
||||
placeholder: {
|
||||
control: "text",
|
||||
description: "Placeholder text for the input",
|
||||
},
|
||||
required: {
|
||||
control: "boolean",
|
||||
description: "Whether the input is required",
|
||||
},
|
||||
inputHint: {
|
||||
control: "select",
|
||||
options: ["text", "code"],
|
||||
description: "Input type hint for styling and behavior",
|
||||
},
|
||||
showMessage: {
|
||||
control: "text",
|
||||
description: "Custom message for show action",
|
||||
},
|
||||
hideMessage: {
|
||||
control: "text",
|
||||
description: "Custom message for hide action",
|
||||
},
|
||||
rows: {
|
||||
control: { type: "number", min: 1, max: 50 },
|
||||
description: "Number of visible text lines",
|
||||
},
|
||||
cols: {
|
||||
control: { type: "number", min: 10, max: 200 },
|
||||
description: "Number of visible character width",
|
||||
},
|
||||
resize: {
|
||||
control: "select",
|
||||
options: ["none", "both", "horizontal", "vertical"],
|
||||
description: "How the textarea can be resized",
|
||||
},
|
||||
wrap: {
|
||||
control: "select",
|
||||
options: ["soft", "hard", "off"],
|
||||
description: "Text wrapping behavior",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default metadata;
|
||||
|
||||
type Story = StoryObj<AkHiddenTextAreaInput>;
|
||||
|
||||
const Template: Story = {
|
||||
args: {
|
||||
label: "Hidden Textarea Input",
|
||||
value: "",
|
||||
revealed: false,
|
||||
rows: 4,
|
||||
},
|
||||
render: (args) => html`
|
||||
<ak-hidden-textarea-input
|
||||
label=${ifDefined(args.label)}
|
||||
value=${ifDefined(args.value)}
|
||||
?revealed=${args.revealed}
|
||||
placeholder=${ifDefined(args.placeholder)}
|
||||
rows=${ifDefined(args.rows)}
|
||||
cols=${ifDefined(args.cols)}
|
||||
resize=${ifDefined(args.resize)}
|
||||
wrap=${ifDefined(args.wrap)}
|
||||
?required=${args.required}
|
||||
input-hint=${ifDefined(args.inputHint)}
|
||||
show-message=${ifDefined(args.showMessage)}
|
||||
hide-message=${ifDefined(args.hideMessage)}
|
||||
></ak-hidden-textarea-input>
|
||||
`,
|
||||
};
|
||||
|
||||
export const SslCertificate: Story = {
|
||||
...Template,
|
||||
args: {
|
||||
label: "SSL Certificate",
|
||||
value: `-----BEGIN CERTIFICATE-----
|
||||
MIIDXTCCAkWgAwIBAgIJAKoK/heBjcOuMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQwHhcNMTcwNTEwMTk0MDA2WhcNMTgwNTEwMTk0MDA2WjBF
|
||||
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
||||
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE3MDUxMDE5NDAwNloXDTE4MDUxMDE5
|
||||
NDAwNlowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNV
|
||||
BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBALdUlNS31SzxwoFShahGfjHj6GgpcVbzL1Siq0Pqnf82T6M2
|
||||
EDuneMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAECggE
|
||||
BAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqn
|
||||
f82T6M2EDuneMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgM
|
||||
BAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAECggEBAJkPFn6jeM
|
||||
Hyiq0Pqnf82T6M2EDuneMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDu
|
||||
neMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAECggEBAJ
|
||||
kPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAE=
|
||||
-----END CERTIFICATE-----`,
|
||||
inputHint: "code",
|
||||
rows: 15,
|
||||
resize: "vertical",
|
||||
showMessage: "Show certificate content",
|
||||
hideMessage: "Hide certificate content",
|
||||
autocomplete: "off",
|
||||
},
|
||||
};
|
121
web/src/components/stories/ak-visibility-toggle.stories.ts
Normal file
121
web/src/components/stories/ak-visibility-toggle.stories.ts
Normal file
@ -0,0 +1,121 @@
|
||||
import type { Meta, StoryObj } from "@storybook/web-components";
|
||||
|
||||
import { html, nothing } from "lit";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import "../ak-visibility-toggle";
|
||||
import { type VisibilityToggle, type VisibilityToggleProps } from "../ak-visibility-toggle.js";
|
||||
|
||||
const metadata: Meta<VisibilityToggleProps> = {
|
||||
title: "Elements/<ak-visibility-toggle>",
|
||||
component: "ak-visibility-toggle",
|
||||
tags: ["autodocs"],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: `
|
||||
# Visibility Toggle Component
|
||||
|
||||
A straightforward two-state iconic button for toggling the visibility of sensitive content such as passwords, private keys, or other secret information.
|
||||
|
||||
- Use for sensitive content that users might want to temporarily reveal
|
||||
- There are default hide/show messages for screen readers, but they can be overridden
|
||||
- Clients always handle the state
|
||||
- The \`open\` state is false by default; we assume you want sensitive content hidden at start
|
||||
`,
|
||||
},
|
||||
},
|
||||
layout: "padded",
|
||||
},
|
||||
argTypes: {
|
||||
open: {
|
||||
control: "boolean",
|
||||
description: "Whether the toggle is in the 'show' state (true) or 'hide' state (false)",
|
||||
},
|
||||
showMessage: {
|
||||
control: "text",
|
||||
description:
|
||||
'Message for screen readers when in hide state (default: "Show field content")',
|
||||
},
|
||||
hideMessage: {
|
||||
control: "text",
|
||||
description:
|
||||
'Message for screen readers when in show state (default: "Hide field content")',
|
||||
},
|
||||
disabled: {
|
||||
control: "boolean",
|
||||
description: "Whether the button should be disabled (for demo purposes)",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default metadata;
|
||||
|
||||
type Story = StoryObj<VisibilityToggle>;
|
||||
|
||||
const Template: Story = {
|
||||
args: {
|
||||
open: false,
|
||||
showMessage: "Show field content",
|
||||
hideMessage: "Hide field content",
|
||||
},
|
||||
render: (args) => html`
|
||||
<ak-visibility-toggle
|
||||
?open=${args.open}
|
||||
show-message=${ifDefined(args.showMessage)}
|
||||
hide-message=${ifDefined(args.hideMessage)}
|
||||
@click=${(e: Event) => {
|
||||
const target = e.target as VisibilityToggle;
|
||||
target.open = !target.open;
|
||||
// In a real application, you would also toggle the visibility
|
||||
// of the associated content here
|
||||
}}
|
||||
></ak-visibility-toggle>
|
||||
`,
|
||||
};
|
||||
|
||||
// Password field integration example
|
||||
export const PasswordFieldExample: Story = {
|
||||
args: {
|
||||
showMessage: "Reveal password",
|
||||
hideMessage: "Conceal password",
|
||||
},
|
||||
render: () => {
|
||||
let isVisible = false;
|
||||
|
||||
const toggleVisibility = (e: Event) => {
|
||||
isVisible = !isVisible;
|
||||
const toggle = e.target as VisibilityToggle;
|
||||
const passwordField = document.querySelector("#demo-password") as HTMLInputElement;
|
||||
|
||||
toggle.open = isVisible;
|
||||
if (passwordField) {
|
||||
passwordField.type = isVisible ? "text" : "password";
|
||||
}
|
||||
};
|
||||
|
||||
return html`
|
||||
<div style="display: flex; flex-direction: column; gap: 1rem; max-width: 300px;">
|
||||
<label for="demo-password" style="font-weight: bold;">Password:</label>
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<input
|
||||
id="demo-password"
|
||||
type="password"
|
||||
value="supersecretpassword123"
|
||||
style="flex: 1; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;"
|
||||
readonly
|
||||
/>
|
||||
<ak-visibility-toggle
|
||||
?open=${isVisible}
|
||||
show-message="Show password"
|
||||
hide-message="Hide password"
|
||||
@click=${toggleVisibility}
|
||||
></ak-visibility-toggle>
|
||||
</div>
|
||||
<p style="font-size: 0.875rem; color: #666;">
|
||||
Click the eye icon to toggle password visibility
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
};
|
@ -16,8 +16,12 @@ import { property } from "lit/decorators.js";
|
||||
|
||||
import { UiThemeEnum } from "@goauthentik/api";
|
||||
|
||||
export interface AKElementProps {
|
||||
activeTheme: ResolvedUITheme;
|
||||
}
|
||||
|
||||
@localized()
|
||||
export class AKElement extends LitElement {
|
||||
export class AKElement extends LitElement implements AKElementProps {
|
||||
//#region Static Properties
|
||||
|
||||
public static styles?: Array<CSSResult | CSSModule>;
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" ?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<?xml version="1.0"?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file target-language="zh-Hans" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
||||
<body>
|
||||
<trans-unit id="s4caed5b7a7e5d89b">
|
||||
@ -596,9 +596,9 @@
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="saa0e2675da69651b">
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>未找到 URL "
|
||||
<x id="0" equiv-text="${this.url}"/>"。</target>
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>未找到 URL "
|
||||
<x id="0" equiv-text="${this.url}"/>"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s58cd9c2fe836d9c6">
|
||||
@ -1709,8 +1709,8 @@
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa90b7809586c35ce">
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。</target>
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s0410779cb47de312">
|
||||
@ -3762,10 +3762,10 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa95a538bfbb86111">
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<target>您确定要更新
|
||||
<x id="0" equiv-text="${this.objectLabel}"/>"
|
||||
<x id="1" equiv-text="${this.obj?.name}"/>" 吗?</target>
|
||||
<x id="0" equiv-text="${this.objectLabel}"/>"
|
||||
<x id="1" equiv-text="${this.obj?.name}"/>" 吗?</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sc92d7cfb6ee1fec6">
|
||||
@ -4831,7 +4831,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sdf1d8edef27236f0">
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<target>像 YubiKey 这样的“漫游”身份验证器</target>
|
||||
|
||||
</trans-unit>
|
||||
@ -5190,7 +5190,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s1608b2f94fa0dbd4">
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<target>如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。</target>
|
||||
|
||||
</trans-unit>
|
||||
@ -7466,7 +7466,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<target>成功创建用户并添加到组 <x id="0" equiv-text="${this.group.name}"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s824e0943a7104668">
|
||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||
<target>此用户将会被添加到组 &quot;<x id="0" equiv-text="${this.targetGroup.name}"/>&quot;。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62e7f6ed7d9cb3ca">
|
||||
@ -8748,7 +8748,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<target>同步组</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d5f69929bb7221d">
|
||||
<source><x id="0" equiv-text="${p.name}"/> ("<x id="1" equiv-text="${p.fieldKey}"/>", of type <x id="2" equiv-text="${p.type}"/>)</source>
|
||||
<source><x id="0" equiv-text="${p.name}"/> ("<x id="1" equiv-text="${p.fieldKey}"/>", of type <x id="2" equiv-text="${p.type}"/>)</source>
|
||||
<target><x id="0" equiv-text="${p.name}"/>(&quot;<x id="1" equiv-text="${p.fieldKey}"/>&quot;,类型为 <x id="2" equiv-text="${p.type}"/>)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s25bacc19d98b444e">
|
||||
@ -8996,8 +8996,8 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<target>授权流程成功后有效的重定向 URI。还可以在此处为隐式流程指定任何来源。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4c49d27de60a532b">
|
||||
<source>To allow any redirect URI, set the mode to Regex and the value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>要允许任何重定向 URI,请设置模式为正则表达式,并将此值设置为 ".*"。请注意这可能带来的安全影响。</target>
|
||||
<source>To allow any redirect URI, set the mode to Regex and the value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>要允许任何重定向 URI,请设置模式为正则表达式,并将此值设置为 ".*"。请注意这可能带来的安全影响。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sa52bf79fe1ccb13e">
|
||||
<source>Federated OIDC Sources</source>
|
||||
@ -9750,7 +9750,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<target>在 authorization_code 令牌请求流程期间,如何执行身份验证</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s844baf19a6c4a9b4">
|
||||
<source>Enable "Remember me on this device"</source>
|
||||
<source>Enable "Remember me on this device"</source>
|
||||
<target>启用“在此设备上记住我”</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sfa72bca733f40692">
|
||||
@ -9883,4 +9883,4 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
</xliff>
|
||||
|
@ -661,12 +661,6 @@
|
||||
<source>Apps with most usage</source>
|
||||
<target>使用率最高的应用</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sda5e1499f93146ad">
|
||||
<source><x id="0" equiv-text="${ago}"/> days ago</source>
|
||||
<target>
|
||||
<x id="0" equiv-text="${ago}"/>天前</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s51ea3a244c781b1f">
|
||||
<source>Objects created</source>
|
||||
@ -6118,21 +6112,11 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<source>Download Private key</source>
|
||||
<target>下载私钥</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s3a5fec3d73ac9edc">
|
||||
<source>Create Certificate-Key Pair</source>
|
||||
<target>创建证书密钥对</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s45cb501abd43ba52">
|
||||
<source>Generate</source>
|
||||
<target>生成</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sf9bddaf910f4eea5">
|
||||
<source>Generate Certificate-Key Pair</source>
|
||||
<target>生成证书密钥对</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="see2bcbc11bb91960">
|
||||
<source>Successfully updated instance.</source>
|
||||
@ -7533,10 +7517,6 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<source>Configure SCIM Provider</source>
|
||||
<target>配置 SCIM 提供程序</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7513372fe60f6387">
|
||||
<source>Event volume</source>
|
||||
<target>事件容量</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s3271da6c18c25b18">
|
||||
<source>Connection settings.</source>
|
||||
<target>连接设置。</target>
|
||||
@ -9888,6 +9868,18 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<trans-unit id="s04bb32ec9f359507">
|
||||
<source>Additional Group DN</source>
|
||||
<target>额外的组 DN</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sb7af25ce6e30d61a">
|
||||
<source>The currently selected policy engine mode is <x id="0" equiv-text="${policyEngineMode.label}"/>:</source>
|
||||
<target>当前所选策略引擎模式为 <x id="0" equiv-text="${policyEngineMode.label}"/>:</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="se1d2545eda4b1600">
|
||||
<source>Import Existing Certificate-Key Pair</source>
|
||||
<target>导入已有的证书密钥对</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sb3d5c0a0501669df">
|
||||
<source>Generate New Certificate-Key Pair</source>
|
||||
<target>生成新的证书密钥对</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -1,15 +1,10 @@
|
||||
Create a `http_top.conf` file in your nginx `conf.d` directory (`/nginx/conf.d/`) with the following content:
|
||||
|
||||
```nginx
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
# Upgrade WebSocket if requested, otherwise use keepalive
|
||||
map $http_upgrade $connection_upgrade_keepalive {
|
||||
default upgrade;
|
||||
'' '';
|
||||
}
|
||||
```
|
||||
|
||||
Use the following nginx template:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
# SSL and VHost configuration
|
||||
listen 443 ssl http2;
|
||||
@ -25,13 +20,13 @@ server {
|
||||
proxy_buffer_size 32k;
|
||||
|
||||
location / {
|
||||
# Put your proxy_pass to your application here, and all the other statements you'll need.
|
||||
# Put your proxy_pass to your application here, and all the other statements you'll need
|
||||
# proxy_pass http://localhost:5000;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header ...
|
||||
# Support for websocket
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade_keepalive;
|
||||
|
||||
##############################
|
||||
# authentik-specific config
|
||||
|
@ -72,7 +72,7 @@ To check if your config has been applied correctly, you can run the following co
|
||||
- `AUTHENTIK_POSTGRESQL__PASSWORD`: Database password, defaults to the environment variable `POSTGRES_PASSWORD`
|
||||
{/* TODO: Temporarily deactivated feature, see https://github.com/goauthentik/authentik/issues/14320 */}
|
||||
{/* - `AUTHENTIK_POSTGRESQL__USE_POOL`: Use a [connection pool](https://docs.djangoproject.com/en/stable/ref/databases/#connection-pool) for PostgreSQL connections. Defaults to `false`. :ak-version[2025.4] */}
|
||||
- `AUTHENTIK_POSTGRESQL__POOL_OPTIONS`: Extra configuration to pass to the [ConnectionPool object](https://www.psycopg.org/psycopg3/docs/api/pool.html#psycopg_pool.ConnectionPool) when it is created. Must be a base64-encoded JSON dictionary. Ignored when `USE_POOL` is set to `false`. :ak-version[2025.4]
|
||||
{/* - `AUTHENTIK_POSTGRESQL__POOL_OPTIONS`: Extra configuration to pass to the [ConnectionPool object](https://www.psycopg.org/psycopg3/docs/api/pool.html#psycopg_pool.ConnectionPool) when it is created. Must be a base64-encoded JSON dictionary. Ignored when `USE_POOL` is set to `false`. :ak-version[2025.4] */}
|
||||
- `AUTHENTIK_POSTGRESQL__USE_PGBOUNCER`: Adjust configuration to support connection to PgBouncer. Deprecated, see below
|
||||
- `AUTHENTIK_POSTGRESQL__USE_PGPOOL`: Adjust configuration to support connection to Pgpool. Deprecated, see below
|
||||
- `AUTHENTIK_POSTGRESQL__SSLMODE`: Strictness of ssl verification. Defaults to `"verify-ca"`
|
||||
|
66
website/package-lock.json
generated
66
website/package-lock.json
generated
@ -19,11 +19,11 @@
|
||||
"@goauthentik/docusaurus-config": "^1.1.0",
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@swc/html-linux-x64-gnu": "1.12.0",
|
||||
"@swc/html-linux-x64-gnu": "1.12.1",
|
||||
"clsx": "^2.1.1",
|
||||
"docusaurus-plugin-openapi-docs": "^4.4.0",
|
||||
"docusaurus-theme-openapi-docs": "^4.4.0",
|
||||
"postcss": "^8.5.4",
|
||||
"postcss": "^8.5.5",
|
||||
"prism-react-renderer": "^2.4.1",
|
||||
"react": "^18.3.1",
|
||||
"react-before-after-slider-component": "^1.1.8",
|
||||
@ -42,7 +42,7 @@
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/lodash": "^4.17.17",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/node": "^24.0.1",
|
||||
"@types/postman-collection": "^3.5.11",
|
||||
"@types/react": "^18.3.22",
|
||||
"@types/semver": "^7.7.0",
|
||||
@ -64,12 +64,12 @@
|
||||
"@rspack/binding-darwin-arm64": "1.3.15",
|
||||
"@rspack/binding-linux-arm64-gnu": "1.3.15",
|
||||
"@rspack/binding-linux-x64-gnu": "1.3.15",
|
||||
"@swc/core-darwin-arm64": "1.12.0",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.0",
|
||||
"@swc/core-linux-x64-gnu": "1.12.0",
|
||||
"@swc/html-darwin-arm64": "1.12.0",
|
||||
"@swc/html-linux-arm64-gnu": "1.12.0",
|
||||
"@swc/html-linux-x64-gnu": "1.12.0",
|
||||
"@swc/core-darwin-arm64": "1.12.1",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.1",
|
||||
"@swc/core-linux-x64-gnu": "1.12.1",
|
||||
"@swc/html-darwin-arm64": "1.12.1",
|
||||
"@swc/html-linux-arm64-gnu": "1.12.1",
|
||||
"@swc/html-linux-x64-gnu": "1.12.1",
|
||||
"lightningcss-darwin-arm64": "1.30.1",
|
||||
"lightningcss-linux-arm64-gnu": "1.30.1",
|
||||
"lightningcss-linux-x64-gnu": "1.30.1"
|
||||
@ -5592,9 +5592,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-arm64": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.0.tgz",
|
||||
"integrity": "sha512-usLr8kC80GDv3pwH2zoEaS279kxtWY0MY3blbMFw7zA8fAjqxa8IDxm3WcgyNLNWckWn4asFfguEwz/Weem3nA==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.1.tgz",
|
||||
"integrity": "sha512-nUjWVcJ3YS2N40ZbKwYO2RJ4+o2tWYRzNOcIQp05FqW0+aoUCVMdAUUzQinPDynfgwVshDAXCKemY8X7nN5MaA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -5640,9 +5640,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.0.tgz",
|
||||
"integrity": "sha512-Al0x33gUVxNY5tutEYpSyv7mze6qQS1ONa0HEwoRxcK9WXsX0NHLTiOSGZoCUS1SsXM37ONlbA6/Bsp1MQyP+g==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.1.tgz",
|
||||
"integrity": "sha512-BxJDIJPq1+aCh9UsaSAN6wo3tuln8UhNXruOrzTI8/ElIig/3sAueDM6Eq7GvZSGGSA7ljhNATMJ0elD7lFatQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -5672,9 +5672,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-gnu": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.0.tgz",
|
||||
"integrity": "sha512-ltIvqNi7H0c5pRawyqjeYSKEIfZP4vv/datT3mwT6BW7muJtd1+KIDCPFLMIQ4wm/h76YQwPocsin3fzmnFdNA==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.1.tgz",
|
||||
"integrity": "sha512-CrYnV8SZIgArQ9LKH0xEF95PKXzX9WkRSc5j55arOSBeDCeDUQk1Bg/iKdnDiuj5HC1hZpvzwMzSBJjv+Z70jA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -5830,9 +5830,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/html-darwin-arm64": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-darwin-arm64/-/html-darwin-arm64-1.12.0.tgz",
|
||||
"integrity": "sha512-okpx8G7xGSPiSekxS4FQu3aR8k+q8nZJCfVKzanQxdZUaCm7YDVUci2Unqp9TvpgZJRA0GOWs1U3QMu2vdr0sQ==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-darwin-arm64/-/html-darwin-arm64-1.12.1.tgz",
|
||||
"integrity": "sha512-vbCqYgBBdoxlsnUe/G6irBJ69LUOrlLVXgdxWxDSZ3YcbnpVmwi5YEeaRvqf4vNzZ/nzBMd4DYl6KK2Qsi0prw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -5878,9 +5878,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/html-linux-arm64-gnu": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-arm64-gnu/-/html-linux-arm64-gnu-1.12.0.tgz",
|
||||
"integrity": "sha512-ImZLbghifCPqQhwbEprv2zojieD0j/RGJ+tkNpJ6DyGqcf5qVFfPgGDe/WDPEHCMbJlAodvp1iKTdLSAdTfaLg==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-arm64-gnu/-/html-linux-arm64-gnu-1.12.1.tgz",
|
||||
"integrity": "sha512-KbqPLtsPVt0/kjp7sUT1APfEtNQUqMam3S0RzJkvuMz9jB2F9DREvj5EG+DPnx2s/kxnDm4sh9vM2sG2xNHErQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -5910,9 +5910,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/html-linux-x64-gnu": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-x64-gnu/-/html-linux-x64-gnu-1.12.0.tgz",
|
||||
"integrity": "sha512-IVFXgsyn0/8e9nfVrQXAdGDFboom0nls7KSOJ/+oXMmdK917wrnYLDt7M4DyRT2c+xJmMxgR6tyaTW8KLAl02w==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-x64-gnu/-/html-linux-x64-gnu-1.12.1.tgz",
|
||||
"integrity": "sha512-9QNCTgCZtyQVifLXqDTW7v4lgaC11v0/iL9OhsSZ19ycJrBmnxBmZtDIbuQrXAIzE1GD8mMOK/GLey2IeceoDQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -6615,9 +6615,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.0.tgz",
|
||||
"integrity": "sha512-yZQa2zm87aRVcqDyH5+4Hv9KYgSdgwX1rFnGvpbzMaC7YAljmhBET93TPiTd3ObwTL+gSpIzPKg5BqVxdCvxKg==",
|
||||
"version": "24.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.1.tgz",
|
||||
"integrity": "sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.8.0"
|
||||
@ -20672,9 +20672,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
|
||||
"integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
|
||||
"version": "8.5.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.5.tgz",
|
||||
"integrity": "sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -37,7 +37,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"docusaurus-plugin-openapi-docs": "^4.4.0",
|
||||
"docusaurus-theme-openapi-docs": "^4.4.0",
|
||||
"postcss": "^8.5.4",
|
||||
"postcss": "^8.5.5",
|
||||
"prism-react-renderer": "^2.4.1",
|
||||
"react": "^18.3.1",
|
||||
"react-before-after-slider-component": "^1.1.8",
|
||||
@ -56,7 +56,7 @@
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/lodash": "^4.17.17",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/node": "^24.0.1",
|
||||
"@types/postman-collection": "^3.5.11",
|
||||
"@types/react": "^18.3.22",
|
||||
"@types/semver": "^7.7.0",
|
||||
@ -75,12 +75,12 @@
|
||||
"@rspack/binding-darwin-arm64": "1.3.15",
|
||||
"@rspack/binding-linux-arm64-gnu": "1.3.15",
|
||||
"@rspack/binding-linux-x64-gnu": "1.3.15",
|
||||
"@swc/core-darwin-arm64": "1.12.0",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.0",
|
||||
"@swc/core-linux-x64-gnu": "1.12.0",
|
||||
"@swc/html-darwin-arm64": "1.12.0",
|
||||
"@swc/html-linux-arm64-gnu": "1.12.0",
|
||||
"@swc/html-linux-x64-gnu": "1.12.0",
|
||||
"@swc/core-darwin-arm64": "1.12.1",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.1",
|
||||
"@swc/core-linux-x64-gnu": "1.12.1",
|
||||
"@swc/html-darwin-arm64": "1.12.1",
|
||||
"@swc/html-linux-arm64-gnu": "1.12.1",
|
||||
"@swc/html-linux-x64-gnu": "1.12.1",
|
||||
"lightningcss-darwin-arm64": "1.30.1",
|
||||
"lightningcss-linux-arm64-gnu": "1.30.1",
|
||||
"lightningcss-linux-x64-gnu": "1.30.1"
|
||||
|
Reference in New Issue
Block a user