Merge branch 'main' into celery-2-dramatiq
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 2025.6.1
|
||||
current_version = 2025.6.2
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
||||
|
2
.github/workflows/ci-main.yml
vendored
2
.github/workflows/ci-main.yml
vendored
@ -202,7 +202,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: web/dist
|
||||
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
|
||||
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
|
||||
- name: prepare web ui
|
||||
if: steps.cache-web.outputs.cache-hit != 'true'
|
||||
working-directory: web
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from os import environ
|
||||
|
||||
__version__ = "2025.6.1"
|
||||
__version__ = "2025.6.2"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
||||
|
||||
|
@ -386,8 +386,23 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
||||
queryset = User.objects.none()
|
||||
ordering = ["username"]
|
||||
serializer_class = UserSerializer
|
||||
search_fields = ["username", "name", "is_active", "email", "uuid", "attributes"]
|
||||
filterset_class = UsersFilter
|
||||
search_fields = ["username", "name", "is_active", "email", "uuid", "attributes"]
|
||||
|
||||
def get_ql_fields(self):
|
||||
from djangoql.schema import BoolField, StrField
|
||||
|
||||
from authentik.enterprise.search.fields import ChoiceSearchField, JSONSearchField
|
||||
|
||||
return [
|
||||
StrField(User, "username"),
|
||||
StrField(User, "name"),
|
||||
StrField(User, "email"),
|
||||
StrField(User, "path"),
|
||||
BoolField(User, "is_active", nullable=True),
|
||||
ChoiceSearchField(User, "type"),
|
||||
JSONSearchField(User, "attributes"),
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
base_qs = User.objects.all().exclude_anonymous()
|
||||
|
@ -114,6 +114,7 @@ class TestApplicationsAPI(APITestCase):
|
||||
self.assertJSONEqual(
|
||||
response.content.decode(),
|
||||
{
|
||||
"autocomplete": {},
|
||||
"pagination": {
|
||||
"next": 0,
|
||||
"previous": 0,
|
||||
@ -167,6 +168,7 @@ class TestApplicationsAPI(APITestCase):
|
||||
self.assertJSONEqual(
|
||||
response.content.decode(),
|
||||
{
|
||||
"autocomplete": {},
|
||||
"pagination": {
|
||||
"next": 0,
|
||||
"previous": 0,
|
||||
|
@ -119,17 +119,17 @@ class TestTrimPasswordHistory(TestCase):
|
||||
[
|
||||
UserPasswordHistory(
|
||||
user=self.user,
|
||||
old_password="hunter1", # nosec B106
|
||||
old_password="hunter1", # nosec
|
||||
created_at=_now - timedelta(days=3),
|
||||
),
|
||||
UserPasswordHistory(
|
||||
user=self.user,
|
||||
old_password="hunter2", # nosec B106
|
||||
old_password="hunter2", # nosec
|
||||
created_at=_now - timedelta(days=2),
|
||||
),
|
||||
UserPasswordHistory(
|
||||
user=self.user,
|
||||
old_password="hunter3", # nosec B106
|
||||
old_password="hunter3", # nosec
|
||||
created_at=_now,
|
||||
),
|
||||
]
|
||||
|
0
authentik/enterprise/search/__init__.py
Normal file
0
authentik/enterprise/search/__init__.py
Normal file
12
authentik/enterprise/search/apps.py
Normal file
12
authentik/enterprise/search/apps.py
Normal file
@ -0,0 +1,12 @@
|
||||
"""Enterprise app config"""
|
||||
|
||||
from authentik.enterprise.apps import EnterpriseConfig
|
||||
|
||||
|
||||
class AuthentikEnterpriseSearchConfig(EnterpriseConfig):
|
||||
"""Enterprise app config"""
|
||||
|
||||
name = "authentik.enterprise.search"
|
||||
label = "authentik_search"
|
||||
verbose_name = "authentik Enterprise.Search"
|
||||
default = True
|
125
authentik/enterprise/search/fields.py
Normal file
125
authentik/enterprise/search/fields.py
Normal file
@ -0,0 +1,125 @@
|
||||
"""DjangoQL search"""
|
||||
|
||||
from collections import OrderedDict, defaultdict
|
||||
from collections.abc import Generator
|
||||
|
||||
from django.db import connection
|
||||
from django.db.models import Model, Q
|
||||
from djangoql.compat import text_type
|
||||
from djangoql.schema import StrField
|
||||
|
||||
|
||||
class JSONSearchField(StrField):
|
||||
"""JSON field for DjangoQL"""
|
||||
|
||||
model: Model
|
||||
|
||||
def __init__(self, model=None, name=None, nullable=None):
|
||||
# Set this in the constructor to not clobber the type variable
|
||||
self.type = "relation"
|
||||
super().__init__(model, name, nullable)
|
||||
|
||||
def get_lookup(self, path, operator, value):
|
||||
search = "__".join(path)
|
||||
op, invert = self.get_operator(operator)
|
||||
q = Q(**{f"{search}{op}": self.get_lookup_value(value)})
|
||||
return ~q if invert else q
|
||||
|
||||
def json_field_keys(self) -> Generator[tuple[str]]:
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
f"""
|
||||
WITH RECURSIVE "{self.name}_keys" AS (
|
||||
SELECT
|
||||
ARRAY[jsonb_object_keys("{self.name}")] AS key_path_array,
|
||||
"{self.name}" -> jsonb_object_keys("{self.name}") AS value
|
||||
FROM {self.model._meta.db_table}
|
||||
WHERE "{self.name}" IS NOT NULL
|
||||
AND jsonb_typeof("{self.name}") = 'object'
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
ck.key_path_array || jsonb_object_keys(ck.value),
|
||||
ck.value -> jsonb_object_keys(ck.value) AS value
|
||||
FROM "{self.name}_keys" ck
|
||||
WHERE jsonb_typeof(ck.value) = 'object'
|
||||
),
|
||||
|
||||
unique_paths AS (
|
||||
SELECT DISTINCT key_path_array
|
||||
FROM "{self.name}_keys"
|
||||
)
|
||||
|
||||
SELECT key_path_array FROM unique_paths;
|
||||
""" # nosec
|
||||
)
|
||||
return (x[0] for x in cursor.fetchall())
|
||||
|
||||
def get_nested_options(self) -> OrderedDict:
|
||||
"""Get keys of all nested objects to show autocomplete"""
|
||||
base_model_name = f"{self.model._meta.app_label}.{self.model._meta.model_name}_{self.name}"
|
||||
|
||||
def recursive_function(parts: list[str], parent_parts: list[str] | None = None):
|
||||
if not parent_parts:
|
||||
parent_parts = []
|
||||
path = parts.pop(0)
|
||||
parent_parts.append(path)
|
||||
relation_key = "_".join(parent_parts)
|
||||
if len(parts) > 1:
|
||||
out_dict = {
|
||||
relation_key: {
|
||||
parts[0]: {
|
||||
"type": "relation",
|
||||
"relation": f"{relation_key}_{parts[0]}",
|
||||
}
|
||||
}
|
||||
}
|
||||
child_paths = recursive_function(parts.copy(), parent_parts.copy())
|
||||
child_paths.update(out_dict)
|
||||
return child_paths
|
||||
else:
|
||||
return {relation_key: {parts[0]: {}}}
|
||||
|
||||
relation_structure = defaultdict(dict)
|
||||
|
||||
for relations in self.json_field_keys():
|
||||
result = recursive_function([base_model_name] + relations)
|
||||
for relation_key, value in result.items():
|
||||
for sub_relation_key, sub_value in value.items():
|
||||
if not relation_structure[relation_key].get(sub_relation_key, None):
|
||||
relation_structure[relation_key][sub_relation_key] = sub_value
|
||||
else:
|
||||
relation_structure[relation_key][sub_relation_key].update(sub_value)
|
||||
|
||||
final_dict = defaultdict(dict)
|
||||
|
||||
for key, value in relation_structure.items():
|
||||
for sub_key, sub_value in value.items():
|
||||
if not sub_value:
|
||||
final_dict[key][sub_key] = {
|
||||
"type": "str",
|
||||
"nullable": True,
|
||||
}
|
||||
else:
|
||||
final_dict[key][sub_key] = sub_value
|
||||
return OrderedDict(final_dict)
|
||||
|
||||
def relation(self) -> str:
|
||||
return f"{self.model._meta.app_label}.{self.model._meta.model_name}_{self.name}"
|
||||
|
||||
|
||||
class ChoiceSearchField(StrField):
|
||||
def __init__(self, model=None, name=None, nullable=None):
|
||||
super().__init__(model, name, nullable, suggest_options=True)
|
||||
|
||||
def get_options(self, search):
|
||||
result = []
|
||||
choices = self._field_choices()
|
||||
if choices:
|
||||
search = search.lower()
|
||||
for c in choices:
|
||||
choice = text_type(c[0])
|
||||
if search in choice.lower():
|
||||
result.append(choice)
|
||||
return result
|
53
authentik/enterprise/search/pagination.py
Normal file
53
authentik/enterprise/search/pagination.py
Normal file
@ -0,0 +1,53 @@
|
||||
from rest_framework.response import Response
|
||||
|
||||
from authentik.api.pagination import Pagination
|
||||
from authentik.enterprise.search.ql import AUTOCOMPLETE_COMPONENT_NAME, QLSearch
|
||||
|
||||
|
||||
class AutocompletePagination(Pagination):
|
||||
|
||||
def paginate_queryset(self, queryset, request, view=None):
|
||||
self.view = view
|
||||
return super().paginate_queryset(queryset, request, view)
|
||||
|
||||
def get_autocomplete(self):
|
||||
schema = QLSearch().get_schema(self.request, self.view)
|
||||
introspections = {}
|
||||
if hasattr(self.view, "get_ql_fields"):
|
||||
from authentik.enterprise.search.schema import AKQLSchemaSerializer
|
||||
|
||||
introspections = AKQLSchemaSerializer().serialize(
|
||||
schema(self.page.paginator.object_list.model)
|
||||
)
|
||||
return introspections
|
||||
|
||||
def get_paginated_response(self, data):
|
||||
previous_page_number = 0
|
||||
if self.page.has_previous():
|
||||
previous_page_number = self.page.previous_page_number()
|
||||
next_page_number = 0
|
||||
if self.page.has_next():
|
||||
next_page_number = self.page.next_page_number()
|
||||
return Response(
|
||||
{
|
||||
"pagination": {
|
||||
"next": next_page_number,
|
||||
"previous": previous_page_number,
|
||||
"count": self.page.paginator.count,
|
||||
"current": self.page.number,
|
||||
"total_pages": self.page.paginator.num_pages,
|
||||
"start_index": self.page.start_index(),
|
||||
"end_index": self.page.end_index(),
|
||||
},
|
||||
"results": data,
|
||||
"autocomplete": self.get_autocomplete(),
|
||||
}
|
||||
)
|
||||
|
||||
def get_paginated_response_schema(self, schema):
|
||||
final_schema = super().get_paginated_response_schema(schema)
|
||||
final_schema["properties"]["autocomplete"] = {
|
||||
"$ref": f"#/components/schemas/{AUTOCOMPLETE_COMPONENT_NAME}"
|
||||
}
|
||||
final_schema["required"].append("autocomplete")
|
||||
return final_schema
|
78
authentik/enterprise/search/ql.py
Normal file
78
authentik/enterprise/search/ql.py
Normal file
@ -0,0 +1,78 @@
|
||||
"""DjangoQL search"""
|
||||
|
||||
from django.apps import apps
|
||||
from django.db.models import QuerySet
|
||||
from djangoql.ast import Name
|
||||
from djangoql.exceptions import DjangoQLError
|
||||
from djangoql.queryset import apply_search
|
||||
from djangoql.schema import DjangoQLSchema
|
||||
from rest_framework.filters import SearchFilter
|
||||
from rest_framework.request import Request
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.enterprise.search.fields import JSONSearchField
|
||||
|
||||
LOGGER = get_logger()
|
||||
AUTOCOMPLETE_COMPONENT_NAME = "Autocomplete"
|
||||
AUTOCOMPLETE_SCHEMA = {
|
||||
"type": "object",
|
||||
"additionalProperties": {},
|
||||
}
|
||||
|
||||
|
||||
class BaseSchema(DjangoQLSchema):
|
||||
"""Base Schema which deals with JSON Fields"""
|
||||
|
||||
def resolve_name(self, name: Name):
|
||||
model = self.model_label(self.current_model)
|
||||
root_field = name.parts[0]
|
||||
field = self.models[model].get(root_field)
|
||||
# If the query goes into a JSON field, return the root
|
||||
# field as the JSON field will do the rest
|
||||
if isinstance(field, JSONSearchField):
|
||||
# This is a workaround; build_filter will remove the right-most
|
||||
# entry in the path as that is intended to be the same as the field
|
||||
# however for JSON that is not the case
|
||||
if name.parts[-1] != root_field:
|
||||
name.parts.append(root_field)
|
||||
return field
|
||||
return super().resolve_name(name)
|
||||
|
||||
|
||||
class QLSearch(SearchFilter):
|
||||
"""rest_framework search filter which uses DjangoQL"""
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return apps.get_app_config("authentik_enterprise").enabled()
|
||||
|
||||
def get_search_terms(self, request) -> str:
|
||||
"""
|
||||
Search terms are set by a ?search=... query parameter,
|
||||
and may be comma and/or whitespace delimited.
|
||||
"""
|
||||
params = request.query_params.get(self.search_param, "")
|
||||
params = params.replace("\x00", "") # strip null characters
|
||||
return params
|
||||
|
||||
def get_schema(self, request: Request, view) -> BaseSchema:
|
||||
ql_fields = []
|
||||
if hasattr(view, "get_ql_fields"):
|
||||
ql_fields = view.get_ql_fields()
|
||||
|
||||
class InlineSchema(BaseSchema):
|
||||
def get_fields(self, model):
|
||||
return ql_fields or []
|
||||
|
||||
return InlineSchema
|
||||
|
||||
def filter_queryset(self, request: Request, queryset: QuerySet, view) -> QuerySet:
|
||||
search_query = self.get_search_terms(request)
|
||||
schema = self.get_schema(request, view)
|
||||
if len(search_query) == 0 or not self.enabled:
|
||||
return super().filter_queryset(request, queryset, view)
|
||||
try:
|
||||
return apply_search(queryset, search_query, schema=schema)
|
||||
except DjangoQLError as exc:
|
||||
LOGGER.debug("Failed to parse search expression", exc=exc)
|
||||
return super().filter_queryset(request, queryset, view)
|
29
authentik/enterprise/search/schema.py
Normal file
29
authentik/enterprise/search/schema.py
Normal file
@ -0,0 +1,29 @@
|
||||
from djangoql.serializers import DjangoQLSchemaSerializer
|
||||
from drf_spectacular.generators import SchemaGenerator
|
||||
|
||||
from authentik.api.schema import create_component
|
||||
from authentik.enterprise.search.fields import JSONSearchField
|
||||
from authentik.enterprise.search.ql import AUTOCOMPLETE_COMPONENT_NAME, AUTOCOMPLETE_SCHEMA
|
||||
|
||||
|
||||
class AKQLSchemaSerializer(DjangoQLSchemaSerializer):
|
||||
def serialize(self, schema):
|
||||
serialization = super().serialize(schema)
|
||||
for _, fields in schema.models.items():
|
||||
for _, field in fields.items():
|
||||
if not isinstance(field, JSONSearchField):
|
||||
continue
|
||||
serialization["models"].update(field.get_nested_options())
|
||||
return serialization
|
||||
|
||||
def serialize_field(self, field):
|
||||
result = super().serialize_field(field)
|
||||
if isinstance(field, JSONSearchField):
|
||||
result["relation"] = field.relation()
|
||||
return result
|
||||
|
||||
|
||||
def postprocess_schema_search_autocomplete(result, generator: SchemaGenerator, **kwargs):
|
||||
create_component(generator, AUTOCOMPLETE_COMPONENT_NAME, AUTOCOMPLETE_SCHEMA)
|
||||
|
||||
return result
|
17
authentik/enterprise/search/settings.py
Normal file
17
authentik/enterprise/search/settings.py
Normal file
@ -0,0 +1,17 @@
|
||||
SPECTACULAR_SETTINGS = {
|
||||
"POSTPROCESSING_HOOKS": [
|
||||
"authentik.api.schema.postprocess_schema_responses",
|
||||
"authentik.enterprise.search.schema.postprocess_schema_search_autocomplete",
|
||||
"drf_spectacular.hooks.postprocess_schema_enums",
|
||||
],
|
||||
}
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_PAGINATION_CLASS": "authentik.enterprise.search.pagination.AutocompletePagination",
|
||||
"DEFAULT_FILTER_BACKENDS": [
|
||||
"authentik.enterprise.search.ql.QLSearch",
|
||||
"authentik.rbac.filters.ObjectFilter",
|
||||
"django_filters.rest_framework.DjangoFilterBackend",
|
||||
"rest_framework.filters.OrderingFilter",
|
||||
],
|
||||
}
|
78
authentik/enterprise/search/tests.py
Normal file
78
authentik/enterprise/search/tests.py
Normal file
@ -0,0 +1,78 @@
|
||||
from json import loads
|
||||
from unittest.mock import PropertyMock, patch
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
|
||||
|
||||
@patch(
|
||||
"authentik.enterprise.audit.middleware.EnterpriseAuditMiddleware.enabled",
|
||||
PropertyMock(return_value=True),
|
||||
)
|
||||
class QLTest(APITestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.user = create_test_admin_user()
|
||||
# ensure we have more than 1 user
|
||||
create_test_admin_user()
|
||||
|
||||
def test_search(self):
|
||||
"""Test simple search query"""
|
||||
self.client.force_login(self.user)
|
||||
query = f'username = "{self.user.username}"'
|
||||
res = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:user-list",
|
||||
)
|
||||
+ f"?{urlencode({"search": query})}"
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
content = loads(res.content)
|
||||
self.assertEqual(content["pagination"]["count"], 1)
|
||||
self.assertEqual(content["results"][0]["username"], self.user.username)
|
||||
|
||||
def test_no_search(self):
|
||||
"""Ensure works with no search query"""
|
||||
self.client.force_login(self.user)
|
||||
res = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:user-list",
|
||||
)
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
content = loads(res.content)
|
||||
self.assertNotEqual(content["pagination"]["count"], 1)
|
||||
|
||||
def test_search_no_ql(self):
|
||||
"""Test simple search query (no QL)"""
|
||||
self.client.force_login(self.user)
|
||||
res = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:user-list",
|
||||
)
|
||||
+ f"?{urlencode({"search": self.user.username})}"
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
content = loads(res.content)
|
||||
self.assertEqual(content["pagination"]["count"], 1)
|
||||
self.assertEqual(content["results"][0]["username"], self.user.username)
|
||||
|
||||
def test_search_json(self):
|
||||
"""Test search query with a JSON attribute"""
|
||||
self.user.attributes = {"foo": {"bar": "baz"}}
|
||||
self.user.save()
|
||||
self.client.force_login(self.user)
|
||||
query = 'attributes.foo.bar = "baz"'
|
||||
res = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:user-list",
|
||||
)
|
||||
+ f"?{urlencode({"search": query})}"
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
content = loads(res.content)
|
||||
self.assertEqual(content["pagination"]["count"], 1)
|
||||
self.assertEqual(content["results"][0]["username"], self.user.username)
|
@ -6,6 +6,7 @@ TENANT_APPS = [
|
||||
"authentik.enterprise.providers.google_workspace",
|
||||
"authentik.enterprise.providers.microsoft_entra",
|
||||
"authentik.enterprise.providers.ssf",
|
||||
"authentik.enterprise.search",
|
||||
"authentik.enterprise.stages.authenticator_endpoint_gdtc",
|
||||
"authentik.enterprise.stages.mtls",
|
||||
"authentik.enterprise.stages.source",
|
||||
|
@ -132,6 +132,21 @@ class EventViewSet(ModelViewSet):
|
||||
]
|
||||
filterset_class = EventsFilter
|
||||
|
||||
def get_ql_fields(self):
|
||||
from djangoql.schema import DateTimeField, StrField
|
||||
|
||||
from authentik.enterprise.search.fields import ChoiceSearchField, JSONSearchField
|
||||
|
||||
return [
|
||||
StrField(Event, "app", suggest_options=True),
|
||||
StrField(Event, "client_ip"),
|
||||
JSONSearchField(Event, "user"),
|
||||
JSONSearchField(Event, "brand"),
|
||||
ChoiceSearchField(Event, "action"),
|
||||
JSONSearchField(Event, "context"),
|
||||
DateTimeField(Event, "created", suggest_options=True),
|
||||
]
|
||||
|
||||
@extend_schema(
|
||||
methods=["GET"],
|
||||
responses={200: EventTopPerUserSerializer(many=True)},
|
||||
|
@ -49,6 +49,7 @@ class TestEndpointsAPI(APITestCase):
|
||||
self.assertJSONEqual(
|
||||
response.content.decode(),
|
||||
{
|
||||
"autocomplete": {},
|
||||
"pagination": {
|
||||
"next": 0,
|
||||
"previous": 0,
|
||||
@ -101,6 +102,7 @@ class TestEndpointsAPI(APITestCase):
|
||||
self.assertJSONEqual(
|
||||
response.content.decode(),
|
||||
{
|
||||
"autocomplete": {},
|
||||
"pagination": {
|
||||
"next": 0,
|
||||
"previous": 0,
|
||||
|
@ -44,6 +44,7 @@ class TestRBACRoleAPI(APITestCase):
|
||||
self.assertJSONEqual(
|
||||
res.content.decode(),
|
||||
{
|
||||
"autocomplete": {},
|
||||
"pagination": {
|
||||
"next": 0,
|
||||
"previous": 0,
|
||||
|
@ -46,6 +46,7 @@ class TestRBACUserAPI(APITestCase):
|
||||
self.assertJSONEqual(
|
||||
res.content.decode(),
|
||||
{
|
||||
"autocomplete": {},
|
||||
"pagination": {
|
||||
"next": 0,
|
||||
"previous": 0,
|
||||
|
@ -38,6 +38,7 @@ class TestAPIPerms(APITestCase):
|
||||
self.assertJSONEqual(
|
||||
res.content.decode(),
|
||||
{
|
||||
"autocomplete": {},
|
||||
"pagination": {
|
||||
"next": 0,
|
||||
"previous": 0,
|
||||
@ -73,6 +74,7 @@ class TestAPIPerms(APITestCase):
|
||||
self.assertJSONEqual(
|
||||
res.content.decode(),
|
||||
{
|
||||
"autocomplete": {},
|
||||
"pagination": {
|
||||
"next": 0,
|
||||
"previous": 0,
|
||||
|
@ -362,8 +362,7 @@ DRAMATIQ = {
|
||||
"dramatiq.middleware.time_limit.TimeLimit",
|
||||
{
|
||||
# 5 minutes task timeout by default for all tasks
|
||||
"time_limit": 600
|
||||
* 1000,
|
||||
"time_limit": 600 * 1000,
|
||||
},
|
||||
),
|
||||
("dramatiq.middleware.shutdown.ShutdownNotifications", {}),
|
||||
@ -450,6 +449,8 @@ _DISALLOWED_ITEMS = [
|
||||
"INSTALLED_APPS",
|
||||
"MIDDLEWARE",
|
||||
"AUTHENTICATION_BACKENDS",
|
||||
"SPECTACULAR_SETTINGS",
|
||||
"REST_FRAMEWORK",
|
||||
]
|
||||
|
||||
SILENCED_SYSTEM_CHECKS = [
|
||||
@ -472,6 +473,8 @@ def _update_settings(app_path: str):
|
||||
TENANT_APPS.extend(getattr(settings_module, "TENANT_APPS", []))
|
||||
MIDDLEWARE.extend(getattr(settings_module, "MIDDLEWARE", []))
|
||||
AUTHENTICATION_BACKENDS.extend(getattr(settings_module, "AUTHENTICATION_BACKENDS", []))
|
||||
SPECTACULAR_SETTINGS.update(getattr(settings_module, "SPECTACULAR_SETTINGS", {}))
|
||||
REST_FRAMEWORK.update(getattr(settings_module, "REST_FRAMEWORK", {}))
|
||||
for _attr in dir(settings_module):
|
||||
if not _attr.startswith("__") and _attr not in _DISALLOWED_ITEMS:
|
||||
globals()[_attr] = getattr(settings_module, _attr)
|
||||
|
@ -2,7 +2,7 @@
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "https://goauthentik.io/blueprints/schema.json",
|
||||
"type": "object",
|
||||
"title": "authentik 2025.6.1 Blueprint schema",
|
||||
"title": "authentik 2025.6.2 Blueprint schema",
|
||||
"required": [
|
||||
"version",
|
||||
"entries"
|
||||
@ -7385,6 +7385,7 @@
|
||||
"authentik.enterprise.providers.google_workspace",
|
||||
"authentik.enterprise.providers.microsoft_entra",
|
||||
"authentik.enterprise.providers.ssf",
|
||||
"authentik.enterprise.search",
|
||||
"authentik.enterprise.stages.authenticator_endpoint_gdtc",
|
||||
"authentik.enterprise.stages.mtls",
|
||||
"authentik.enterprise.stages.source",
|
||||
|
@ -31,7 +31,7 @@ services:
|
||||
volumes:
|
||||
- redis:/data
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
@ -55,7 +55,7 @@ services:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
|
4
go.mod
4
go.mod
@ -18,7 +18,7 @@ require (
|
||||
github.com/gorilla/sessions v1.4.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/grafana/pyroscope-go v1.2.2
|
||||
github.com/jellydator/ttlcache/v3 v3.3.0
|
||||
github.com/jellydator/ttlcache/v3 v3.4.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
||||
github.com/pires/go-proxyproto v0.8.1
|
||||
@ -29,7 +29,7 @@ require (
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/wwt/guac v1.3.2
|
||||
goauthentik.io/api/v3 v3.2025061.2
|
||||
goauthentik.io/api/v3 v3.2025062.1
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.15.0
|
||||
|
8
go.sum
8
go.sum
@ -203,8 +203,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
|
||||
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
|
||||
github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
|
||||
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
@ -298,8 +298,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
goauthentik.io/api/v3 v3.2025061.2 h1:bKmrl82Gz6J8lz3f+QIH9g+MEkl3MvkMXF34GktesA0=
|
||||
goauthentik.io/api/v3 v3.2025061.2/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
goauthentik.io/api/v3 v3.2025062.1 h1:spvILDpDDWJNO3pM6QGqmryx6NvSchr1E8H60J/XUCA=
|
||||
goauthentik.io/api/v3 v3.2025062.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
@ -33,4 +33,4 @@ func UserAgent() string {
|
||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||
}
|
||||
|
||||
const VERSION = "2025.6.1"
|
||||
const VERSION = "2025.6.2"
|
||||
|
@ -26,7 +26,7 @@ Parameters:
|
||||
Description: authentik Docker image
|
||||
AuthentikVersion:
|
||||
Type: String
|
||||
Default: 2025.6.1
|
||||
Default: 2025.6.2
|
||||
Description: authentik Docker image tag
|
||||
AuthentikServerCPU:
|
||||
Type: Number
|
||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@goauthentik/authentik",
|
||||
"version": "2025.6.1",
|
||||
"version": "2025.6.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@goauthentik/authentik",
|
||||
"version": "2025.6.1",
|
||||
"version": "2025.6.2",
|
||||
"devDependencies": {
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"prettier": "^3.3.3",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@goauthentik/authentik",
|
||||
"version": "2025.6.1",
|
||||
"version": "2025.6.2",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
126
packages/eslint-config/package-lock.json
generated
126
packages/eslint-config/package-lock.json
generated
@ -576,17 +576,17 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
|
||||
"integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
|
||||
"integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/type-utils": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/type-utils": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
@ -600,7 +600,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.34.0",
|
||||
"@typescript-eslint/parser": "^8.34.1",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
@ -616,16 +616,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
|
||||
"integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
|
||||
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -641,14 +641,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
|
||||
"integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
|
||||
"integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.34.0",
|
||||
"@typescript-eslint/types": "^8.34.0",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.34.1",
|
||||
"@typescript-eslint/types": "^8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -663,14 +663,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
|
||||
"integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
|
||||
"integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -681,9 +681,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
|
||||
"integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -698,14 +698,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
|
||||
"integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
@ -722,9 +722,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
|
||||
"integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
|
||||
"integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -736,16 +736,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
|
||||
"integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
|
||||
"integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.34.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"@typescript-eslint/project-service": "8.34.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -765,9 +765,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -804,16 +804,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
|
||||
"integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
|
||||
"integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.0"
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -828,14 +828,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
|
||||
"integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
|
||||
"integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -4035,15 +4035,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz",
|
||||
"integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
|
||||
"integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.34.0",
|
||||
"@typescript-eslint/parser": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.34.1",
|
||||
"@typescript-eslint/parser": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "authentik"
|
||||
version = "2025.6.1"
|
||||
version = "2025.6.2"
|
||||
description = ""
|
||||
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
|
||||
requires-python = "==3.13.*"
|
||||
@ -23,11 +23,12 @@ dependencies = [
|
||||
"django-pglock==1.7.2",
|
||||
"django-pgtrigger==4.15.2",
|
||||
"django-prometheus==2.3.1",
|
||||
"django-redis==5.4.0",
|
||||
"django-redis==6.0.0",
|
||||
"django-storages[s3]==1.14.6",
|
||||
"django-tenants==3.8.0",
|
||||
"djangorestframework==3.16.0",
|
||||
"djangoql==0.18.1",
|
||||
"djangorestframework-guardian==0.3.0",
|
||||
"djangorestframework==3.16.0",
|
||||
"docker==7.1.0",
|
||||
"dramatiq[watch]==1.17.1",
|
||||
"drf-orjson-renderer==1.7.3",
|
||||
@ -70,7 +71,7 @@ dependencies = [
|
||||
"urllib3<3",
|
||||
"uvicorn[standard]==0.34.3",
|
||||
"watchdog==6.0.0",
|
||||
"webauthn==2.5.2",
|
||||
"webauthn==2.6.0",
|
||||
"wsproto==1.2.0",
|
||||
"xmlsec==1.3.15",
|
||||
"zxcvbn==4.5.0",
|
||||
|
417
schema.yml
417
schema.yml
File diff suppressed because it is too large
Load Diff
59
uv.lock
generated
59
uv.lock
generated
@ -159,7 +159,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "authentik"
|
||||
version = "2025.6.1"
|
||||
version = "2025.6.2"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "argon2-cffi" },
|
||||
@ -183,6 +183,7 @@ dependencies = [
|
||||
{ name = "django-redis" },
|
||||
{ name = "django-storages", extra = ["s3"] },
|
||||
{ name = "django-tenants" },
|
||||
{ name = "djangoql" },
|
||||
{ name = "djangorestframework" },
|
||||
{ name = "djangorestframework-guardian" },
|
||||
{ name = "docker" },
|
||||
@ -280,9 +281,10 @@ requires-dist = [
|
||||
{ name = "django-pglock", specifier = "==1.7.2" },
|
||||
{ name = "django-pgtrigger", specifier = "==4.15.2" },
|
||||
{ name = "django-prometheus", specifier = "==2.3.1" },
|
||||
{ name = "django-redis", specifier = "==5.4.0" },
|
||||
{ name = "django-redis", specifier = "==6.0.0" },
|
||||
{ name = "django-storages", extras = ["s3"], specifier = "==1.14.6" },
|
||||
{ name = "django-tenants", specifier = "==3.8.0" },
|
||||
{ name = "djangoql", specifier = "==0.18.1" },
|
||||
{ name = "djangorestframework", git = "https://github.com/goauthentik/django-rest-framework?rev=896722bab969fabc74a08b827da59409cf9f1a4e" },
|
||||
{ name = "djangorestframework-guardian", specifier = "==0.3.0" },
|
||||
{ name = "docker", specifier = "==7.1.0" },
|
||||
@ -327,7 +329,7 @@ requires-dist = [
|
||||
{ name = "urllib3", specifier = "<3" },
|
||||
{ name = "uvicorn", extras = ["standard"], specifier = "==0.34.3" },
|
||||
{ name = "watchdog", specifier = "==6.0.0" },
|
||||
{ name = "webauthn", specifier = "==2.5.2" },
|
||||
{ name = "webauthn", specifier = "==2.6.0" },
|
||||
{ name = "wsproto", specifier = "==1.2.0" },
|
||||
{ name = "xmlsec", specifier = "==1.3.15" },
|
||||
{ name = "zxcvbn", specifier = "==4.5.0" },
|
||||
@ -1055,15 +1057,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "django-redis"
|
||||
version = "5.4.0"
|
||||
version = "6.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
{ name = "redis" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/83/9d/2272742fdd9d0a9f0b28cd995b0539430c9467a2192e4de2cea9ea6ad38c/django-redis-5.4.0.tar.gz", hash = "sha256:6a02abaa34b0fea8bf9b707d2c363ab6adc7409950b2db93602e6cb292818c42", size = 52567, upload-time = "2023-10-01T20:22:01.221Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/08/53/dbcfa1e528e0d6c39947092625b2c89274b5d88f14d357cee53c4d6dbbd4/django_redis-6.0.0.tar.gz", hash = "sha256:2d9cb12a20424a4c4dde082c6122f486628bae2d9c2bee4c0126a4de7fda00dd", size = 56904, upload-time = "2025-06-17T18:15:46.376Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/f1/63caad7c9222c26a62082f4f777de26389233b7574629996098bf6d25a4d/django_redis-5.4.0-py3-none-any.whl", hash = "sha256:ebc88df7da810732e2af9987f7f426c96204bf89319df4c6da6ca9a2942edd5b", size = 31119, upload-time = "2023-10-01T20:21:33.009Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/79/055dfcc508cfe9f439d9f453741188d633efa9eab90fc78a67b0ab50b137/django_redis-6.0.0-py3-none-any.whl", hash = "sha256:20bf0063a8abee567eb5f77f375143c32810c8700c0674ced34737f8de4e36c0", size = 33687, upload-time = "2025-06-17T18:15:34.165Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1092,6 +1094,17 @@ dependencies = [
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a8/7b/22e3bb79d48e5a4fdcacdcdc27bbc5c2523a2b7892b440bfe229f313d823/django_tenants-3.8.0.tar.gz", hash = "sha256:07d009d5d01be2d65c3f5ddbf323d58d1228838fc1a64fded15c8e5c6f41cf8f", size = 154307, upload-time = "2025-05-23T16:07:24.307Z" }
|
||||
|
||||
[[package]]
|
||||
name = "djangoql"
|
||||
version = "0.18.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "ply" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/0a/83cdb7b9d3b854b98941363153945f6c051b3bc50cd61108a85677c98c3a/djangoql-0.18.1-py2.py3-none-any.whl", hash = "sha256:51b3085a805627ebb43cfd0aa861137cdf8f69cc3c9244699718fe04a6c8e26d", size = 218209, upload-time = "2024-01-08T14:10:47.915Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "djangorestframework"
|
||||
version = "3.16.0"
|
||||
@ -2299,6 +2312,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ply"
|
||||
version = "3.11"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", size = 159130, upload-time = "2018-02-15T19:01:31.097Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce", size = 49567, upload-time = "2018-02-15T19:01:27.172Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometheus-client"
|
||||
version = "0.22.1"
|
||||
@ -3079,6 +3101,25 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tornado"
|
||||
version = "6.5.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/51/89/c72771c81d25d53fe33e3dca61c233b665b2780f21820ba6fd2c6793c12b/tornado-6.5.1.tar.gz", hash = "sha256:84ceece391e8eb9b2b95578db65e920d2a61070260594819589609ba9bc6308c", size = 509934, upload-time = "2025-05-22T18:15:38.788Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/77/89/f4532dee6843c9e0ebc4e28d4be04c67f54f60813e4bf73d595fe7567452/tornado-6.5.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d50065ba7fd11d3bd41bcad0825227cc9a95154bad83239357094c36708001f7", size = 441948, upload-time = "2025-05-22T18:15:20.862Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/9a/557406b62cffa395d18772e0cdcf03bed2fff03b374677348eef9f6a3792/tornado-6.5.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9e9ca370f717997cb85606d074b0e5b247282cf5e2e1611568b8821afe0342d6", size = 440112, upload-time = "2025-05-22T18:15:22.591Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/82/7721b7319013a3cf881f4dffa4f60ceff07b31b394e459984e7a36dc99ec/tornado-6.5.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b77e9dfa7ed69754a54c89d82ef746398be82f749df69c4d3abe75c4d1ff4888", size = 443672, upload-time = "2025-05-22T18:15:24.027Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/42/d11c4376e7d101171b94e03cef0cbce43e823ed6567ceda571f54cf6e3ce/tornado-6.5.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253b76040ee3bab8bcf7ba9feb136436a3787208717a1fb9f2c16b744fba7331", size = 443019, upload-time = "2025-05-22T18:15:25.735Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/f7/0c48ba992d875521ac761e6e04b0a1750f8150ae42ea26df1852d6a98942/tornado-6.5.1-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:308473f4cc5a76227157cdf904de33ac268af770b2c5f05ca6c1161d82fdd95e", size = 443252, upload-time = "2025-05-22T18:15:27.499Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/46/d8d7413d11987e316df4ad42e16023cd62666a3c0dfa1518ffa30b8df06c/tornado-6.5.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:caec6314ce8a81cf69bd89909f4b633b9f523834dc1a352021775d45e51d9401", size = 443930, upload-time = "2025-05-22T18:15:29.299Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/b2/f8049221c96a06df89bed68260e8ca94beca5ea532ffc63b1175ad31f9cc/tornado-6.5.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:13ce6e3396c24e2808774741331638ee6c2f50b114b97a55c5b442df65fd9692", size = 443351, upload-time = "2025-05-22T18:15:31.038Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/ff/6a0079e65b326cc222a54720a748e04a4db246870c4da54ece4577bfa702/tornado-6.5.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5cae6145f4cdf5ab24744526cc0f55a17d76f02c98f4cff9daa08ae9a217448a", size = 443328, upload-time = "2025-05-22T18:15:32.426Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/18/e3f902a1d21f14035b5bc6246a8c0f51e0eef562ace3a2cea403c1fb7021/tornado-6.5.1-cp39-abi3-win32.whl", hash = "sha256:e0a36e1bc684dca10b1aa75a31df8bdfed656831489bc1e6a6ebed05dc1ec365", size = 444396, upload-time = "2025-05-22T18:15:34.205Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/09/6526e32bf1049ee7de3bebba81572673b19a2a8541f795d887e92af1a8bc/tornado-6.5.1-cp39-abi3-win_amd64.whl", hash = "sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b", size = 444840, upload-time = "2025-05-22T18:15:36.1Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/a7/535c44c7bea4578e48281d83c615219f3ab19e6abc67625ef637c73987be/tornado-6.5.1-cp39-abi3-win_arm64.whl", hash = "sha256:02420a0eb7bf617257b9935e2b754d1b63897525d8a289c9d65690d580b4dcf7", size = 443596, upload-time = "2025-05-22T18:15:37.433Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trio"
|
||||
version = "0.30.0"
|
||||
@ -3347,7 +3388,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "webauthn"
|
||||
version = "2.5.2"
|
||||
version = "2.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asn1crypto" },
|
||||
@ -3355,9 +3396,9 @@ dependencies = [
|
||||
{ name = "cryptography" },
|
||||
{ name = "pyopenssl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8d/92/8d2a4eec83d8e7feacdaad37c6eb6eb922100cecce5c14a41d8069a59a03/webauthn-2.5.2.tar.gz", hash = "sha256:09c13dfc1c68c810f32fa4d89b1d37acb9f9ae9091c9d7019e313be4525a95ef", size = 124114, upload-time = "2025-03-07T19:44:05.243Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/63/38/5792cb2034673c162a721df0ad65825699516ee0c938a65670ad3cdabf6c/webauthn-2.6.0.tar.gz", hash = "sha256:13cf5b009a64cef569599ffecf24550df1d7c0cd4fbaea870f937148484a80b4", size = 123608, upload-time = "2025-06-16T22:25:26.76Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/fe/f6ae41de9f383439e30b303a67f6f45d2fceabedaedc34c62f74d58c5c73/webauthn-2.5.2-py3-none-any.whl", hash = "sha256:44246e496e617eb5e2f51165046b9f0197fcdf470f69cd6734061a27ba365f8e", size = 71624, upload-time = "2025-03-07T19:44:03.728Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/c5/b1bba7f6a50caca77f37003e098f48f8dc68d990aba8a03ac8376016430b/webauthn-2.6.0-py3-none-any.whl", hash = "sha256:459973eb5780c1f41bec42b682acf587456b185733398a0b99a0714705b79447", size = 71189, upload-time = "2025-06-16T22:25:25.535Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
207
web/package-lock.json
generated
207
web/package-lock.json
generated
@ -22,16 +22,17 @@
|
||||
"@floating-ui/dom": "^1.6.11",
|
||||
"@formatjs/intl-listformat": "^7.7.11",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@goauthentik/api": "^2025.6.1-1749515784",
|
||||
"@goauthentik/api": "^2025.6.2-1750242193",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@lit/localize": "^0.12.2",
|
||||
"@lit/reactive-element": "^2.0.4",
|
||||
"@lit/task": "^1.0.2",
|
||||
"@mdx-js/mdx": "^3.1.0",
|
||||
"@mrmarble/djangoql-completion": "^0.8.3",
|
||||
"@open-wc/lit-helpers": "^0.7.0",
|
||||
"@patternfly/elements": "^4.1.0",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@sentry/browser": "^9.29.0",
|
||||
"@sentry/browser": "^9.30.0",
|
||||
"@spotlightjs/spotlight": "^3.0.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"change-case": "^5.4.4",
|
||||
@ -123,7 +124,7 @@
|
||||
"storybook-addon-mock": "^5.0.0",
|
||||
"turnstile-types": "^1.2.3",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.34.0",
|
||||
"typescript-eslint": "^8.34.1",
|
||||
"vite-plugin-lit-css": "^2.0.0",
|
||||
"vite-tsconfig-paths": "^5.0.1",
|
||||
"wireit": "^0.14.12"
|
||||
@ -1728,9 +1729,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@goauthentik/api": {
|
||||
"version": "2025.6.1-1749515784",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2025.6.1-1749515784.tgz",
|
||||
"integrity": "sha512-0yN4vJ2/grtNz6OVNMW34gd6TylBeyTSoH1Zlr7e2yeAbg+oZB8WmpLLCZGqvOguYGN6vYEYrPQF1k3RJohmlQ=="
|
||||
"version": "2025.6.2-1750242193",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2025.6.2-1750242193.tgz",
|
||||
"integrity": "sha512-yAi3LbxGP1pyu/lV+iiJp2FrIhOa9/nMErdiy4KC2uh63AS74iqNpYb4/IIbkCeT8fbSSNKhAbA6gXE9zFZ6Yg=="
|
||||
},
|
||||
"node_modules/@goauthentik/core": {
|
||||
"resolved": "packages/core",
|
||||
@ -2660,6 +2661,16 @@
|
||||
"langium": "3.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@mrmarble/djangoql-completion": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@mrmarble/djangoql-completion/-/djangoql-completion-0.8.3.tgz",
|
||||
"integrity": "sha512-wYctvF0gQs48wL9jLQ+H2g2B0yJj7CrUSNi4ec5gcSuICIRqD/QSt6G+3zDdeW1LlI/4uj/FByJvg8k4TAAnVg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lex": "1.7.9",
|
||||
"lodash": "4.17.21"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/nice": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.0.1.tgz",
|
||||
@ -4479,75 +4490,75 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sentry-internal/browser-utils": {
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.29.0.tgz",
|
||||
"integrity": "sha512-Wp6UJCDVV2KVK+TG8GwdLZyDy4GtUYDmVhGMpHKPS3G/Qgpf36cY/XHwChwaHZ5P9Bk1sjS9Ok698J59S8L2nw==",
|
||||
"version": "9.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.30.0.tgz",
|
||||
"integrity": "sha512-e6ZlN8oWheCB0YJSGlBNUlh6UPnY5Ecj1P+/cgeKBhNm7c3bIx4J50485hB8LQsu+b7Q11L2o/wucZ//Pb6FCg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "9.29.0"
|
||||
"@sentry/core": "9.30.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/feedback": {
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.29.0.tgz",
|
||||
"integrity": "sha512-ADvetGrtr+RfYcQKrQxah4fHs/xDJ/VjbStVMSuaNllzwWPYNkWIGFE6YjQ7wZszj0DQIu5/H+B6lZKsFYk4xw==",
|
||||
"version": "9.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.30.0.tgz",
|
||||
"integrity": "sha512-qAZ7xxLqZM7GlEvmSUmTHnoueg+fc7esMQD4vH8pS7HI3n9C5MjGn3HHlndRpD8lL7iUUQ0TPZQgU6McbzMDyw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "9.29.0"
|
||||
"@sentry/core": "9.30.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/replay": {
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.29.0.tgz",
|
||||
"integrity": "sha512-we/1JPRje8sNowQCyogOV1OYWuDOP/3XmDi48XoFG2HB0XMl2HfL5LI8AvgAvC/5nrqVAAo4ktbjoVLm1fb7rg==",
|
||||
"version": "9.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.30.0.tgz",
|
||||
"integrity": "sha512-+6wkqQGLJuFUzvGRzbh3iIhFGyxQx/Oxc0ODDKmz9ag2xYRjCYb3UUQXmQX9navAF0HXUsq8ajoJPm2L1ZyWVg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/browser-utils": "9.29.0",
|
||||
"@sentry/core": "9.29.0"
|
||||
"@sentry-internal/browser-utils": "9.30.0",
|
||||
"@sentry/core": "9.30.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/replay-canvas": {
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.29.0.tgz",
|
||||
"integrity": "sha512-TrQYhSAVPhyenvu0fNkon7BznFibu1mzS5bCudxhgOWajZluUVrXcbp8Q3WZ3R+AogrcgA3Vy6aumP/+fMKdwg==",
|
||||
"version": "9.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.30.0.tgz",
|
||||
"integrity": "sha512-I4MxS27rfV7vnOU29L80y4baZ4I1XqpnYvC/yLN7C17nA8eDCufQ8WVomli41y8JETnfcxlm68z7CS0sO4RCSA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/replay": "9.29.0",
|
||||
"@sentry/core": "9.29.0"
|
||||
"@sentry-internal/replay": "9.30.0",
|
||||
"@sentry/core": "9.30.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.29.0.tgz",
|
||||
"integrity": "sha512-+GFX/yb+rh6V1fSgTYM6ttAgledl2aUR3T3Rg86HNuegbdX8ym6lOtUOIZ0j9jPK015HR47KIPyIZVZZJ7Rj9g==",
|
||||
"version": "9.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.30.0.tgz",
|
||||
"integrity": "sha512-sRyW6A9nIieTTI26MYXk1DmWEhmphTjZevusNWla+vvUigCmSjuH+xZw19w43OyvF3bu261Skypnm/mAalOTwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/browser-utils": "9.29.0",
|
||||
"@sentry-internal/feedback": "9.29.0",
|
||||
"@sentry-internal/replay": "9.29.0",
|
||||
"@sentry-internal/replay-canvas": "9.29.0",
|
||||
"@sentry/core": "9.29.0"
|
||||
"@sentry-internal/browser-utils": "9.30.0",
|
||||
"@sentry-internal/feedback": "9.30.0",
|
||||
"@sentry-internal/replay": "9.30.0",
|
||||
"@sentry-internal/replay-canvas": "9.30.0",
|
||||
"@sentry/core": "9.30.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.29.0.tgz",
|
||||
"integrity": "sha512-wDyNe45PM+RCGtUn1tK7LzJ08ksv8i8KRUHrst7lsinEfRm83YH+wbWrPmwkVNEngUZvYkHwGLbNXM7xgFUuDQ==",
|
||||
"version": "9.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.30.0.tgz",
|
||||
"integrity": "sha512-JfEpeQ8a1qVJEb9DxpFTFy1J1gkNdlgKAPiqYGNnm4yQbnfl2Kb/iEo1if70FkiHc52H8fJwISEF90pzMm6lPg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@ -7345,17 +7356,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
|
||||
"integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
|
||||
"integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/type-utils": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/type-utils": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
@ -7369,7 +7380,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.34.0",
|
||||
"@typescript-eslint/parser": "^8.34.1",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
@ -7385,16 +7396,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
|
||||
"integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
|
||||
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -7410,14 +7421,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
|
||||
"integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
|
||||
"integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.34.0",
|
||||
"@typescript-eslint/types": "^8.34.0",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.34.1",
|
||||
"@typescript-eslint/types": "^8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -7432,14 +7443,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
|
||||
"integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
|
||||
"integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -7450,9 +7461,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
|
||||
"integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -7467,14 +7478,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
|
||||
"integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
@ -7491,9 +7502,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
|
||||
"integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
|
||||
"integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -7505,16 +7516,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
|
||||
"integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
|
||||
"integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.34.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"@typescript-eslint/project-service": "8.34.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -7534,16 +7545,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
|
||||
"integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
|
||||
"integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.0"
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -7558,14 +7569,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
|
||||
"integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
|
||||
"integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -18978,6 +18989,12 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lex": {
|
||||
"version": "1.7.9",
|
||||
"resolved": "https://registry.npmjs.org/lex/-/lex-1.7.9.tgz",
|
||||
"integrity": "sha512-vzaalVBmFLnMaedq0QAsBAaXsWahzRpvnIBdBjj7y+7EKTS6lnziU2y/PsU2c6rV5qYj2B5IDw0uNJ9peXD0vw==",
|
||||
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."
|
||||
},
|
||||
"node_modules/lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
@ -26933,15 +26950,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz",
|
||||
"integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
|
||||
"integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.34.0",
|
||||
"@typescript-eslint/parser": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.34.1",
|
||||
"@typescript-eslint/parser": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -93,16 +93,17 @@
|
||||
"@floating-ui/dom": "^1.6.11",
|
||||
"@formatjs/intl-listformat": "^7.7.11",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@goauthentik/api": "^2025.6.1-1749515784",
|
||||
"@goauthentik/api": "^2025.6.2-1750242193",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@lit/localize": "^0.12.2",
|
||||
"@lit/reactive-element": "^2.0.4",
|
||||
"@lit/task": "^1.0.2",
|
||||
"@mdx-js/mdx": "^3.1.0",
|
||||
"@mrmarble/djangoql-completion": "^0.8.3",
|
||||
"@open-wc/lit-helpers": "^0.7.0",
|
||||
"@patternfly/elements": "^4.1.0",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@sentry/browser": "^9.29.0",
|
||||
"@sentry/browser": "^9.30.0",
|
||||
"@spotlightjs/spotlight": "^3.0.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"change-case": "^5.4.4",
|
||||
@ -194,7 +195,7 @@
|
||||
"storybook-addon-mock": "^5.0.0",
|
||||
"turnstile-types": "^1.2.3",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.34.0",
|
||||
"typescript-eslint": "^8.34.1",
|
||||
"vite-plugin-lit-css": "^2.0.0",
|
||||
"vite-tsconfig-paths": "^5.0.1",
|
||||
"wireit": "^0.14.12"
|
||||
|
2
web/packages/core/types/node.d.ts
vendored
2
web/packages/core/types/node.d.ts
vendored
@ -14,7 +14,7 @@ declare module "module" {
|
||||
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
||||
* ```
|
||||
*/
|
||||
// eslint-disable-next-line no-var
|
||||
|
||||
var __dirname: string;
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,8 @@ export class RecentEventsCard extends Table<Event> {
|
||||
}
|
||||
|
||||
return super.renderEmpty(
|
||||
html`<ak-empty-state header=${msg("No Events found.")}>
|
||||
html`<ak-empty-state
|
||||
><span slot="header">${msg("No Events found.")}</span>
|
||||
<div slot="body">${msg("No matching events could be found.")}</div>
|
||||
</ak-empty-state>`,
|
||||
);
|
||||
|
@ -5,6 +5,7 @@ import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-file-input";
|
||||
import "@goauthentik/components/ak-radio-input";
|
||||
import "@goauthentik/components/ak-slug-input";
|
||||
import "@goauthentik/components/ak-switch-input";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
import "@goauthentik/components/ak-textarea-input";
|
||||
@ -130,14 +131,14 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
|
||||
required
|
||||
help=${msg("Application's display Name.")}
|
||||
></ak-text-input>
|
||||
<ak-text-input
|
||||
<ak-slug-input
|
||||
name="slug"
|
||||
value=${ifDefined(this.instance?.slug)}
|
||||
label=${msg("Slug")}
|
||||
required
|
||||
help=${msg("Internal application name used in URLs.")}
|
||||
input-hint="code"
|
||||
></ak-text-input>
|
||||
></ak-slug-input>
|
||||
<ak-text-input
|
||||
name="group"
|
||||
value=${ifDefined(this.instance?.group)}
|
||||
|
@ -117,13 +117,11 @@ export class ApplicationWizardApplicationStep extends ApplicationWizardStep {
|
||||
?invalid=${this.errors.has("name")}
|
||||
.errorMessages=${errors.name ?? this.errorMessages("name")}
|
||||
help=${msg("Application's display Name.")}
|
||||
id="ak-application-wizard-details-name"
|
||||
></ak-text-input>
|
||||
<ak-slug-input
|
||||
name="slug"
|
||||
value=${ifDefined(app.slug)}
|
||||
label=${msg("Slug")}
|
||||
source="#ak-application-wizard-details-name"
|
||||
required
|
||||
?invalid=${errors.slug ?? this.errors.has("slug")}
|
||||
.errorMessages=${this.errorMessages("slug")}
|
||||
|
@ -115,7 +115,8 @@ export class ApplicationWizardBindingsStep extends ApplicationWizardStep {
|
||||
.columns=${COLUMNS}
|
||||
.content=${[]}
|
||||
></ak-select-table>
|
||||
<ak-empty-state header=${msg("No bound policies.")} icon="pf-icon-module">
|
||||
<ak-empty-state icon="pf-icon-module"
|
||||
><span slot="header">${msg("No bound policies.")} </span>
|
||||
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
||||
<div slot="primary">
|
||||
<button
|
||||
|
@ -20,6 +20,7 @@ import { Event, EventsApi } from "@goauthentik/api";
|
||||
@customElement("ak-event-list")
|
||||
export class EventListPage extends TablePage<Event> {
|
||||
expandable = true;
|
||||
supportsQL = true;
|
||||
|
||||
pageTitle(): string {
|
||||
return msg("Event Log");
|
||||
|
@ -135,7 +135,8 @@ export class BoundStagesList extends Table<FlowStageBinding> {
|
||||
|
||||
renderEmpty(): TemplateResult {
|
||||
return super.renderEmpty(
|
||||
html`<ak-empty-state header=${msg("No Stages bound")} icon="pf-icon-module">
|
||||
html`<ak-empty-state icon="pf-icon-module">
|
||||
<span slot="header">${msg("No Stages bound")}</span>
|
||||
<div slot="body">${msg("No stages are currently bound to this flow.")}</div>
|
||||
<div slot="primary">
|
||||
<ak-stage-wizard
|
||||
|
@ -3,6 +3,7 @@ import { DesignationToLabel, LayoutToLabel } from "@goauthentik/admin/flows/util
|
||||
import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes";
|
||||
import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-slug-input.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
@ -91,17 +92,16 @@ export class FlowForm extends WithCapabilitiesConfig(ModelForm<Flow, string>) {
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">${msg("Shown as the Title in Flow pages.")}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.slug)}"
|
||||
class="pf-c-form-control pf-m-monospace"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
required
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">${msg("Visible in the URL.")}</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-slug-input
|
||||
name="slug"
|
||||
value=${ifDefined(this.instance?.slug)}
|
||||
label=${msg("Slug")}
|
||||
required
|
||||
help=${msg("Visible in the URL.")}
|
||||
input-hint="code"
|
||||
></ak-slug-input>
|
||||
|
||||
<ak-form-element-horizontal label=${msg("Designation")} required name="designation">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.instance?.designation === undefined}>
|
||||
|
@ -198,7 +198,8 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||
|
||||
renderEmpty(): TemplateResult {
|
||||
return super.renderEmpty(
|
||||
html`<ak-empty-state header=${msg("No Policies bound.")} icon="pf-icon-module">
|
||||
html`<ak-empty-state icon="pf-icon-module"
|
||||
><span slot="header">${msg("No Policies bound.")}</span>
|
||||
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
||||
<div slot="primary">
|
||||
<ak-policy-wizard
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-secret-text-input.js";
|
||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
||||
import "@goauthentik/components/ak-slug-input.js";
|
||||
import "@goauthentik/components/ak-switch-input";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
import "@goauthentik/components/ak-textarea-input";
|
||||
@ -87,12 +88,13 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
||||
value=${ifDefined(this.instance?.name)}
|
||||
required
|
||||
></ak-text-input>
|
||||
<ak-text-input
|
||||
<ak-slug-input
|
||||
name="slug"
|
||||
label=${msg("Slug")}
|
||||
value=${ifDefined(this.instance?.slug)}
|
||||
label=${msg("Slug")}
|
||||
required
|
||||
></ak-text-input>
|
||||
input-hint="code"
|
||||
></ak-slug-input>
|
||||
<ak-switch-input
|
||||
name="enabled"
|
||||
?checked=${this.instance?.enabled ?? true}
|
||||
|
@ -3,6 +3,7 @@ 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-secret-text-input.js";
|
||||
import "@goauthentik/components/ak-slug-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";
|
||||
@ -54,14 +55,15 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.slug)}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-slug-input
|
||||
name="slug"
|
||||
value=${ifDefined(this.instance?.slug)}
|
||||
label=${msg("Slug")}
|
||||
required
|
||||
input-hint="code"
|
||||
></ak-slug-input>
|
||||
|
||||
<ak-form-element-horizontal name="enabled">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-radio-input";
|
||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
||||
import "@goauthentik/components/ak-slug-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";
|
||||
@ -267,16 +268,13 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.slug)}"
|
||||
class="pf-c-form-control pf-m-monospace"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-slug-input
|
||||
name="slug"
|
||||
value=${ifDefined(this.instance?.slug)}
|
||||
label=${msg("Slug")}
|
||||
required
|
||||
input-hint="code"
|
||||
></ak-slug-input>
|
||||
<ak-form-element-horizontal name="enabled">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
|
||||
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-slug-input.js";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
|
||||
@ -183,14 +184,15 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.slug)}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-slug-input
|
||||
name="slug"
|
||||
value=${ifDefined(this.instance?.slug)}
|
||||
label=${msg("Slug")}
|
||||
required
|
||||
input-hint="code"
|
||||
></ak-slug-input>
|
||||
|
||||
<ak-form-element-horizontal name="enabled">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
UserMatchingModeToLabel,
|
||||
} from "@goauthentik/admin/sources/oauth/utils";
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/components/ak-slug-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";
|
||||
@ -89,14 +90,15 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.slug)}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-slug-input
|
||||
name="slug"
|
||||
value=${ifDefined(this.instance?.slug)}
|
||||
label=${msg("Slug")}
|
||||
required
|
||||
input-hint="code"
|
||||
></ak-slug-input>
|
||||
|
||||
<ak-form-element-horizontal name="enabled">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
|
@ -1,6 +1,7 @@
|
||||
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-slug-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";
|
||||
@ -48,14 +49,15 @@ export class SCIMSourceForm extends BaseSourceForm<SCIMSource> {
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.slug)}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-slug-input
|
||||
name="slug"
|
||||
value=${ifDefined(this.instance?.slug)}
|
||||
label=${msg("Slug")}
|
||||
required
|
||||
input-hint="code"
|
||||
></ak-slug-input>
|
||||
|
||||
<ak-form-element-horizontal name="enabled">
|
||||
<div class="pf-c-check">
|
||||
<input
|
||||
|
@ -41,14 +41,27 @@ export class InvitationForm extends ModelForm<Invitation, string> {
|
||||
}
|
||||
|
||||
renderForm(): TemplateResult {
|
||||
return html` <ak-form-element-horizontal slugMode label=${msg("Name")} required name="name">
|
||||
const checkSlug = (ev: InputEvent) => {
|
||||
if (ev && ev.target && ev.target instanceof HTMLInputElement) {
|
||||
ev.target.value = (ev.target.value ?? "").replace(/[^a-z0-9-]/g, "");
|
||||
}
|
||||
};
|
||||
|
||||
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
|
||||
<input
|
||||
type="text"
|
||||
id="admin-stages-invitation-name"
|
||||
value="${this.instance?.name || ""}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
@input=${(ev: InputEvent) => checkSlug(ev)}
|
||||
data-ak-slug="true"
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Expires")} required name="expires">
|
||||
<input
|
||||
|
@ -85,6 +85,7 @@ export class UserListPage extends WithBrandConfig(WithCapabilitiesConfig(TablePa
|
||||
expandable = true;
|
||||
checkbox = true;
|
||||
clearOnRefresh = true;
|
||||
supportsQL = true;
|
||||
|
||||
searchEnabled(): boolean {
|
||||
return true;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { me } from "@goauthentik/common/users.js";
|
||||
import { isUserRoute } from "@goauthentik/elements/router/utils.js";
|
||||
import { deepmerge, deepmergeInto } from "deepmerge-ts";
|
||||
|
||||
import { UiThemeEnum, UserSelf } from "@goauthentik/api";
|
||||
import { CurrentBrand } from "@goauthentik/api";
|
||||
@ -96,13 +97,12 @@ export class DefaultUIConfig implements UIConfig {
|
||||
let globalUiConfig: Promise<UIConfig>;
|
||||
|
||||
export function getConfigForUser(user: UserSelf): UIConfig {
|
||||
const settings = user.settings;
|
||||
let config = new DefaultUIConfig();
|
||||
const settings = user.settings as UIConfig;
|
||||
const config = new DefaultUIConfig();
|
||||
if (!settings) {
|
||||
return config;
|
||||
}
|
||||
config = Object.assign(new DefaultUIConfig(), settings);
|
||||
return config;
|
||||
return deepmerge({ ...config }, settings);
|
||||
}
|
||||
|
||||
export function uiConfig(): Promise<UIConfig> {
|
||||
|
306
web/src/components/ak-search-ql/index.ts
Normal file
306
web/src/components/ak-search-ql/index.ts
Normal file
@ -0,0 +1,306 @@
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/buttons/Dropdown";
|
||||
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
|
||||
import DjangoQL, { Introspections } from "@mrmarble/djangoql-completion";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||
import PFSearchInput from "@patternfly/patternfly/components/SearchInput/search-input.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
export class QL extends DjangoQL {
|
||||
createCompletionElement() {
|
||||
this.completionEnabled = !!this.options.completionEnabled;
|
||||
return;
|
||||
}
|
||||
logError(message: string): void {
|
||||
console.warn(`authentik/ql: ${message}`);
|
||||
}
|
||||
textareaResize() {}
|
||||
}
|
||||
|
||||
@customElement("ak-search-ql")
|
||||
export class QLSearch extends AKElement {
|
||||
@property()
|
||||
value?: string;
|
||||
|
||||
@query("[name=search]")
|
||||
searchElement?: HTMLTextAreaElement;
|
||||
|
||||
@state()
|
||||
menuOpen = false;
|
||||
|
||||
@property()
|
||||
onSearch?: (value: string) => void;
|
||||
|
||||
@state()
|
||||
selected?: number;
|
||||
|
||||
@state()
|
||||
cursorX: number = 0;
|
||||
|
||||
@state()
|
||||
cursorY: number = 0;
|
||||
|
||||
ql?: QL;
|
||||
canvas?: CanvasRenderingContext2D;
|
||||
|
||||
set apiResponse(value: PaginatedResponse<unknown> | undefined) {
|
||||
if (!value || !value.autocomplete || !this.ql) {
|
||||
return;
|
||||
}
|
||||
this.ql.loadIntrospections(value.autocomplete as unknown as Introspections);
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
PFBase,
|
||||
PFFormControl,
|
||||
PFSearchInput,
|
||||
css`
|
||||
::-webkit-search-cancel-button {
|
||||
display: none;
|
||||
}
|
||||
.ql.pf-c-form-control {
|
||||
font-family: monospace;
|
||||
resize: vertical;
|
||||
height: 2.25em;
|
||||
}
|
||||
.selected {
|
||||
background-color: var(--pf-c-search-input__menu-item--hover--BackgroundColor);
|
||||
}
|
||||
:host([theme="dark"]) .pf-c-search-input__menu {
|
||||
--pf-c-search-input__menu--BackgroundColor: var(--ak-dark-background-light-ish);
|
||||
color: var(--ak-dark-foreground);
|
||||
}
|
||||
:host([theme="dark"]) .pf-c-search-input__menu-item {
|
||||
--pf-c-search-input__menu-item--Color: var(--ak-dark-foreground);
|
||||
}
|
||||
:host([theme="dark"]) .pf-c-search-input__menu-item:hover {
|
||||
--pf-c-search-input__menu-item--BackgroundColor: var(
|
||||
--ak-dark-background-lighter
|
||||
);
|
||||
}
|
||||
:host([theme="dark"]) .pf-c-search-input__menu-list-item.selected {
|
||||
--pf-c-search-input__menu-item--hover--BackgroundColor: var(
|
||||
--ak-dark-background-light
|
||||
);
|
||||
}
|
||||
:host([theme="dark"]) .pf-c-search-input__text::before {
|
||||
border: 0;
|
||||
}
|
||||
.pf-c-search-input__menu {
|
||||
position: fixed;
|
||||
min-width: 0;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
if (!this.searchElement) {
|
||||
return;
|
||||
}
|
||||
this.ql = new QL({
|
||||
completionEnabled: true,
|
||||
introspections: {
|
||||
current_model: "",
|
||||
models: {},
|
||||
},
|
||||
selector: this.searchElement,
|
||||
autoResize: false,
|
||||
});
|
||||
const canvas = document.createElement("canvas");
|
||||
const context = canvas.getContext("2d");
|
||||
if (!context) {
|
||||
console.error("authentik/ql: failed to get canvas context");
|
||||
return;
|
||||
}
|
||||
context.font = window.getComputedStyle(this.searchElement).font;
|
||||
this.canvas = context;
|
||||
}
|
||||
|
||||
refreshCompletions() {
|
||||
this.value = this.searchElement?.value;
|
||||
if (!this.ql) {
|
||||
return;
|
||||
}
|
||||
this.ql.generateSuggestions();
|
||||
if (this.ql.suggestions.length < 1 || this.ql.loading) {
|
||||
this.menuOpen = false;
|
||||
return;
|
||||
}
|
||||
this.menuOpen = true;
|
||||
this.updateDropdownPosition();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
updateDropdownPosition() {
|
||||
if (!this.searchElement) {
|
||||
return;
|
||||
}
|
||||
const bcr = this.getBoundingClientRect();
|
||||
// We need the width of a letter to measure x; we use a monospaced font but still
|
||||
// check the length for `m` as its the widest ASCII char
|
||||
const metrics = this.canvas?.measureText("m");
|
||||
const letterWidth = Math.ceil(metrics?.width || 0) + 1;
|
||||
|
||||
// Mostly static variables for padding, font line-height and how many
|
||||
const lineHeight = parseInt(window.getComputedStyle(this.searchElement).lineHeight, 10);
|
||||
const paddingTop = parseInt(window.getComputedStyle(this.searchElement).paddingTop, 10);
|
||||
const paddingLeft = parseInt(window.getComputedStyle(this.searchElement).paddingLeft, 10);
|
||||
const paddingRight = parseInt(window.getComputedStyle(this.searchElement).paddingRight, 10);
|
||||
const actualInnerWidth = bcr.width - paddingLeft - paddingRight;
|
||||
|
||||
let relX = 0;
|
||||
let relY = 1;
|
||||
let letterIndex = 0;
|
||||
|
||||
this.searchElement.value.split(" ").some((word, idx) => {
|
||||
letterIndex += word.length;
|
||||
const newRelX = relX + word.length * letterWidth;
|
||||
if (newRelX > actualInnerWidth) {
|
||||
relY += 1;
|
||||
if (letterIndex > this.searchElement!.selectionStart) {
|
||||
relX =
|
||||
letterWidth * word.length -
|
||||
(letterIndex - this.searchElement!.selectionStart) * letterWidth;
|
||||
return true;
|
||||
}
|
||||
relX = word.length * letterWidth;
|
||||
} else {
|
||||
relX = newRelX + 1;
|
||||
}
|
||||
});
|
||||
|
||||
this.cursorX = bcr.x + paddingLeft + relX;
|
||||
this.cursorY = bcr.y + paddingTop + relY * lineHeight;
|
||||
}
|
||||
|
||||
onKeyDown(ev: KeyboardEvent) {
|
||||
this.updateDropdownPosition();
|
||||
if (ev.key === "Enter" && ev.metaKey && this.onSearch && this.searchElement) {
|
||||
this.onSearch(this.searchElement?.value);
|
||||
return;
|
||||
}
|
||||
if (!this.menuOpen) return;
|
||||
switch (ev.key) {
|
||||
case "ArrowUp":
|
||||
if (this.ql?.suggestions.length) {
|
||||
if (this.selected === undefined) {
|
||||
this.selected = this.ql?.suggestions.length - 1;
|
||||
} else if (this.selected === 0) {
|
||||
this.selected = undefined;
|
||||
} else {
|
||||
this.selected -= 1;
|
||||
}
|
||||
this.refreshCompletions();
|
||||
ev.preventDefault();
|
||||
}
|
||||
break;
|
||||
case "ArrowDown":
|
||||
if (this.ql?.suggestions.length) {
|
||||
if (this.selected === undefined) {
|
||||
this.selected = 0;
|
||||
} else if (this.selected < this.ql?.suggestions.length - 1) {
|
||||
this.selected += 1;
|
||||
} else {
|
||||
this.selected = undefined;
|
||||
}
|
||||
this.refreshCompletions();
|
||||
ev.preventDefault();
|
||||
}
|
||||
break;
|
||||
case "Tab":
|
||||
if (this.selected) {
|
||||
this.ql?.selectCompletion(this.selected);
|
||||
ev.preventDefault();
|
||||
}
|
||||
break;
|
||||
case "Enter":
|
||||
// Technically this is a textarea, due to automatic multi-line feature,
|
||||
// but other than that it should look and behave like a normal input.
|
||||
// So expected behavior when pressing Enter is to submit the form,
|
||||
// not to add a new line.
|
||||
if (this.selected !== undefined) {
|
||||
this.ql?.selectCompletion(this.selected);
|
||||
}
|
||||
ev.preventDefault();
|
||||
break;
|
||||
case "Escape":
|
||||
this.menuOpen = false;
|
||||
break;
|
||||
case "Shift": // Shift
|
||||
case "Control": // Ctrl
|
||||
case "Alt": // Alt
|
||||
case "Meta": // Windows Key or Cmd on Mac
|
||||
// Control keys shouldn't trigger completion popup
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
renderMenu() {
|
||||
if (!this.menuOpen || !this.ql) {
|
||||
return nothing;
|
||||
}
|
||||
return html`
|
||||
<div
|
||||
class="pf-c-search-input__menu"
|
||||
style="left: ${this.cursorX}px; top: ${this.cursorY}px;"
|
||||
>
|
||||
<ul class="pf-c-search-input__menu-list">
|
||||
${this.ql.suggestions.map((suggestion, idx) => {
|
||||
return html`<li
|
||||
class="pf-c-search-input__menu-list-item ${this.selected === idx
|
||||
? "selected"
|
||||
: ""}"
|
||||
>
|
||||
<button
|
||||
class="pf-c-search-input__menu-item"
|
||||
type="button"
|
||||
@click=${() => {
|
||||
this.ql?.selectCompletion(idx);
|
||||
this.refreshCompletions();
|
||||
}}
|
||||
>
|
||||
<span class="pf-c-search-input__menu-item-text"
|
||||
>${suggestion.text}</span
|
||||
>
|
||||
</button>
|
||||
</li>`;
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
return html`<div class="pf-c-search-input">
|
||||
<div class="pf-c-search-input__bar">
|
||||
<span class="pf-c-search-input__text">
|
||||
<textarea
|
||||
class="pf-c-form-control ql"
|
||||
name="search"
|
||||
placeholder=${msg("Search...")}
|
||||
spellcheck="false"
|
||||
@input=${(ev: InputEvent) => this.refreshCompletions()}
|
||||
@keydown=${this.onKeyDown}
|
||||
>
|
||||
${ifDefined(this.value)}</textarea
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
${this.renderMenu()}
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ak-search-ql": QLSearch;
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { formatSlug } from "@goauthentik/elements/router/utils.js";
|
||||
import { bound } from "@goauthentik/elements/decorators/bound.js";
|
||||
import { kebabCase } from "change-case";
|
||||
|
||||
import { html } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators.js";
|
||||
@ -6,59 +7,83 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { HorizontalLightComponent } from "./HorizontalLightComponent";
|
||||
|
||||
const slugify = (s: string) => kebabCase(s, { suffixCharacters: "-" });
|
||||
|
||||
/**
|
||||
* @element ak-slug-input
|
||||
* @class AkSlugInput
|
||||
*
|
||||
* A wrapper around `ak-form-element-horizontal` and a text input control that listens for input on
|
||||
* a peer text input control and automatically mirrors that control's value, transforming the value
|
||||
* into a slug and displaying it separately.
|
||||
*
|
||||
* If the user manually changes the slug, mirroring and transformation stop. If, after that, both
|
||||
* fields are cleared manually, mirroring and transformation resume.
|
||||
*
|
||||
* ## Limitations:
|
||||
*
|
||||
* Both the source text field and the slug field must be rendered in the same render pass (i.e.,
|
||||
* part of the same singular call to a `render` function) so that the slug field can find its
|
||||
* source.
|
||||
*
|
||||
* For the same reason, both the source text field and the slug field must share the same immediate
|
||||
* parent DOM object.
|
||||
*
|
||||
* Since we expect the source text field and the slug to be part of the same form and rendered not
|
||||
* just in the same form but in the same form group, these are not considered burdensome
|
||||
* restrictions.
|
||||
*/
|
||||
@customElement("ak-slug-input")
|
||||
export class AkSlugInput extends HorizontalLightComponent<string> {
|
||||
@property({ type: String, reflect: true })
|
||||
value = "";
|
||||
|
||||
/**
|
||||
* A selector indicating the source text input control. Must be unique within the whole DOM
|
||||
* context of the slug and source controls. The most common use in authentik is the default:
|
||||
* slugifying the "name" of something.
|
||||
*/
|
||||
@property({ type: String })
|
||||
source = "";
|
||||
public source = "[name='name']";
|
||||
|
||||
origin?: HTMLInputElement | null;
|
||||
@property({ type: String, reflect: true })
|
||||
public value = "";
|
||||
|
||||
@query("input")
|
||||
input!: HTMLInputElement;
|
||||
private input!: HTMLInputElement;
|
||||
|
||||
touched: boolean = false;
|
||||
#origin?: HTMLInputElement | null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.slugify = this.slugify.bind(this);
|
||||
this.handleTouch = this.handleTouch.bind(this);
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
this.input.addEventListener("input", this.handleTouch);
|
||||
}
|
||||
#touched: boolean = false;
|
||||
|
||||
// Do not stop propagation of this event; it must be sent up the tree so that a parent
|
||||
// component, such as a custom forms manager, may receive it.
|
||||
handleTouch(ev: Event) {
|
||||
this.input.value = formatSlug(this.input.value);
|
||||
this.value = this.input.value;
|
||||
protected handleTouch(ev: Event) {
|
||||
this.value = this.input.value = slugify(this.input.value);
|
||||
|
||||
if (this.origin && this.origin.value === "" && this.input.value === "") {
|
||||
this.touched = false;
|
||||
// Reset 'touched' status if the slug & target have been reset
|
||||
if (this.#origin && this.#origin.value === "" && this.input.value === "") {
|
||||
this.#touched = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev && ev.target && ev.target instanceof HTMLInputElement) {
|
||||
this.touched = true;
|
||||
this.#touched = true;
|
||||
}
|
||||
}
|
||||
|
||||
slugify(ev: Event) {
|
||||
@bound
|
||||
protected slugify(ev: Event) {
|
||||
if (!(ev && ev.target && ev.target instanceof HTMLInputElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset 'touched' status if the slug & target have been reset
|
||||
if (ev.target.value === "" && this.input.value === "") {
|
||||
this.touched = false;
|
||||
this.#touched = false;
|
||||
}
|
||||
|
||||
// Don't proceed if the user has hand-modified the slug
|
||||
if (this.touched) {
|
||||
// Don't proceed if the user has hand-modified the slug. (Note the order of statements: if
|
||||
// the user hand modified the slug to be empty as part of resetting the slug/source
|
||||
// relationship, that's a "not-touched" condition and falls through.)
|
||||
if (this.#touched) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -67,7 +92,7 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
|
||||
// "any event which adds or removes a character but leaves the rest of the slug looking like
|
||||
// the previous iteration, set it to the current iteration."
|
||||
|
||||
const newSlug = formatSlug(ev.target.value);
|
||||
const newSlug = slugify(ev.target.value);
|
||||
const oldSlug = this.input.value;
|
||||
const [shorter, longer] =
|
||||
newSlug.length < oldSlug.length ? [newSlug, oldSlug] : [oldSlug, newSlug];
|
||||
@ -81,7 +106,6 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
|
||||
// to listeners, both the name and value of the host must match those of the target
|
||||
// input. The name is already handled since it's both required and automatically
|
||||
// forwarded to our templated input, but the value must also be set.
|
||||
|
||||
this.value = this.input.value = newSlug;
|
||||
this.dispatchEvent(
|
||||
new Event("input", {
|
||||
@ -91,38 +115,36 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
|
||||
);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
// Set up listener on source element, so we can slugify the content.
|
||||
setTimeout(() => {
|
||||
if (this.source) {
|
||||
const rootNode = this.getRootNode();
|
||||
if (rootNode instanceof ShadowRoot || rootNode instanceof Document) {
|
||||
this.origin = rootNode.querySelector(this.source);
|
||||
}
|
||||
if (this.origin) {
|
||||
this.origin.addEventListener("input", this.slugify);
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.origin) {
|
||||
this.origin.removeEventListener("input", this.slugify);
|
||||
public override disconnectedCallback() {
|
||||
if (this.#origin) {
|
||||
this.#origin.removeEventListener("input", this.slugify);
|
||||
}
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
renderControl() {
|
||||
public override renderControl() {
|
||||
return html`<input
|
||||
@input=${(ev: Event) => this.handleTouch(ev)}
|
||||
type="text"
|
||||
value=${ifDefined(this.value)}
|
||||
class="pf-c-form-control"
|
||||
?required=${this.required}
|
||||
/>`;
|
||||
}
|
||||
|
||||
public override firstUpdated() {
|
||||
if (!this.source) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rootNode = this.getRootNode();
|
||||
if (rootNode instanceof ShadowRoot || rootNode instanceof Document) {
|
||||
this.#origin = rootNode.querySelector(this.source);
|
||||
}
|
||||
if (this.#origin) {
|
||||
this.#origin.addEventListener("input", this.slugify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default AkSlugInput;
|
||||
|
@ -94,7 +94,8 @@ export class ObjectChangelog extends Table<Event> {
|
||||
|
||||
renderEmpty(): TemplateResult {
|
||||
return super.renderEmpty(
|
||||
html`<ak-empty-state header=${msg("No Events found.")}>
|
||||
html`<ak-empty-state
|
||||
><span slot="header">${msg("No Events found.")}</span>
|
||||
<div slot="body">${msg("No matching events could be found.")}</div>
|
||||
</ak-empty-state>`,
|
||||
);
|
||||
|
@ -66,7 +66,8 @@ export class UserEvents extends Table<Event> {
|
||||
|
||||
renderEmpty(): TemplateResult {
|
||||
return super.renderEmpty(
|
||||
html`<ak-empty-state header=${msg("No Events found.")}>
|
||||
html`<ak-empty-state
|
||||
><span slot="header">${msg("No Events found.")}</span>
|
||||
<div slot="body">${msg("No matching events could be found.")}</div>
|
||||
</ak-empty-state>`,
|
||||
);
|
||||
|
@ -3,6 +3,7 @@ import { AKElement } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/Spinner";
|
||||
import { type SlottedTemplateResult, type Spread } from "@goauthentik/elements/types";
|
||||
import { spread } from "@open-wc/lit-helpers";
|
||||
import { SlotController } from "@patternfly/pfe-core/controllers/slot-controller.js";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { css, html, nothing } from "lit";
|
||||
@ -33,6 +34,8 @@ export class EmptyState extends AKElement implements IEmptyState {
|
||||
@property()
|
||||
header?: string;
|
||||
|
||||
slots = new SlotController(this, "header", "body", "primary");
|
||||
|
||||
static get styles() {
|
||||
return [
|
||||
PFBase,
|
||||
@ -48,6 +51,12 @@ export class EmptyState extends AKElement implements IEmptyState {
|
||||
}
|
||||
|
||||
render() {
|
||||
const showHeader = this.loading || this.slots.hasSlotted("header");
|
||||
const header = () =>
|
||||
this.slots.hasSlotted("header")
|
||||
? html`<slot name="header"></slot>`
|
||||
: html`<span>${msg("Loading")}</span>`;
|
||||
|
||||
return html`<div class="pf-c-empty-state ${this.fullHeight && "pf-m-full-height"}">
|
||||
<div class="pf-c-empty-state__content">
|
||||
${this.loading
|
||||
@ -59,15 +68,17 @@ export class EmptyState extends AKElement implements IEmptyState {
|
||||
"fa-question-circle"} pf-c-empty-state__icon"
|
||||
aria-hidden="true"
|
||||
></i>`}
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
${this.loading && this.header === undefined ? msg("Loading") : this.header}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
<slot name="body"></slot>
|
||||
</div>
|
||||
<div class="pf-c-empty-state__primary">
|
||||
<slot name="primary"></slot>
|
||||
</div>
|
||||
${showHeader ? html` <h1 class="pf-c-title pf-m-lg">${header()}</h1>` : nothing}
|
||||
${this.slots.hasSlotted("body")
|
||||
? html` <div class="pf-c-empty-state__body">
|
||||
<slot name="body"></slot>
|
||||
</div>`
|
||||
: nothing}
|
||||
${this.slots.hasSlotted("primary")
|
||||
? html` <div class="pf-c-empty-state__primary">
|
||||
<slot name="primary"></slot>
|
||||
</div>`
|
||||
: nothing}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
@ -200,7 +200,8 @@ export abstract class AKChart<T> extends AKElement {
|
||||
<div class="container">
|
||||
${this.error
|
||||
? html`
|
||||
<ak-empty-state header="${msg("Failed to fetch data.")}" icon="fa-times">
|
||||
<ak-empty-state icon="fa-times"
|
||||
><span slot="header">${msg("Failed to fetch data.")}</span>
|
||||
<p slot="body">${pluckErrorDetail(this.error)}</p>
|
||||
</ak-empty-state>
|
||||
`
|
||||
|
@ -40,7 +40,9 @@ export class LogViewer extends Table<LogEvent> {
|
||||
|
||||
renderEmpty(): TemplateResult {
|
||||
return super.renderEmpty(
|
||||
html`<ak-empty-state header=${msg("No log messages.")}> </ak-empty-state>`,
|
||||
html`<ak-empty-state
|
||||
><span slot="header">${msg("No log messages.")}</span>
|
||||
</ak-empty-state>`,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { PreventFormSubmit } from "@goauthentik/elements/forms/helpers";
|
||||
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
|
||||
import { formatSlug } from "@goauthentik/elements/router/utils.js";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
@ -197,39 +196,6 @@ export abstract class Form<T> extends AKElement {
|
||||
return this.successMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* After rendering the form, if there is both a `name` and `slug` element within the form,
|
||||
* events the `name` element so that the slug will always have a slugified version of the
|
||||
* `name.`. This duplicates functionality within ak-form-element-horizontal.
|
||||
*/
|
||||
updated(): void {
|
||||
this.shadowRoot
|
||||
?.querySelectorAll("ak-form-element-horizontal[name=name]")
|
||||
.forEach((nameInput) => {
|
||||
const input = nameInput.firstElementChild as HTMLInputElement;
|
||||
const form = nameInput.closest("form");
|
||||
if (form === null) {
|
||||
return;
|
||||
}
|
||||
const slugFieldWrapper = form.querySelector(
|
||||
"ak-form-element-horizontal[name=slug]",
|
||||
);
|
||||
if (!slugFieldWrapper) {
|
||||
return;
|
||||
}
|
||||
const slugField = slugFieldWrapper.firstElementChild as HTMLInputElement;
|
||||
// Only attach handler if the slug is already equal to the name
|
||||
// if not, they are probably completely different and shouldn't update
|
||||
// each other
|
||||
if (formatSlug(input.value) !== slugField.value) {
|
||||
return;
|
||||
}
|
||||
nameInput.addEventListener("input", () => {
|
||||
slugField.value = formatSlug(input.value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
resetForm(): void {
|
||||
const form = this.shadowRoot?.querySelector<HTMLFormElement>("form");
|
||||
form?.reset();
|
||||
|
@ -77,9 +77,6 @@ export class HorizontalFormElement extends AKElement {
|
||||
@property({ attribute: false })
|
||||
errorMessages: string[] | string[][] = [];
|
||||
|
||||
@property({ type: Boolean })
|
||||
slugMode = false;
|
||||
|
||||
_invalid = false;
|
||||
|
||||
/* If this property changes, we want to make sure the parent control is "opened" so
|
||||
@ -109,13 +106,6 @@ export class HorizontalFormElement extends AKElement {
|
||||
this.querySelectorAll<HTMLInputElement>("input[autofocus]").forEach((input) => {
|
||||
input.focus();
|
||||
});
|
||||
if (this.name === "slug" || this.slugMode) {
|
||||
this.querySelectorAll<HTMLInputElement>("input[type='text']").forEach((input) => {
|
||||
input.addEventListener("keyup", () => {
|
||||
input.value = formatSlug(input.value);
|
||||
});
|
||||
});
|
||||
}
|
||||
this.querySelectorAll("*").forEach((input) => {
|
||||
if (isAkControl(input) && !input.getAttribute("name")) {
|
||||
input.setAttribute("name", this.name);
|
||||
|
@ -163,7 +163,8 @@ export class NotificationDrawer extends AKElement {
|
||||
}
|
||||
|
||||
renderEmpty() {
|
||||
return html`<ak-empty-state header=${msg("No notifications found.")}>
|
||||
return html`<ak-empty-state
|
||||
><span slot="header">${msg("No notifications found.")}</span>
|
||||
<div slot="body">${msg("You don't have any notifications currently.")}</div>
|
||||
</ak-empty-state>`;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { WithLicenseSummary } from "#elements/mixins/license";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import {
|
||||
APIError,
|
||||
@ -31,13 +32,20 @@ import PFToolbar from "@patternfly/patternfly/components/Toolbar/toolbar.css";
|
||||
import PFBullseye from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
import { Pagination } from "@goauthentik/api";
|
||||
import { LicenseSummaryStatusEnum, Pagination } from "@goauthentik/api";
|
||||
|
||||
export interface TableLike {
|
||||
order?: string;
|
||||
fetch: () => void;
|
||||
}
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
pagination: Pagination;
|
||||
autocomplete?: { [key: string]: string };
|
||||
|
||||
results: Array<T>;
|
||||
}
|
||||
|
||||
export class TableColumn {
|
||||
title: string;
|
||||
orderBy?: string;
|
||||
@ -94,19 +102,16 @@ export class TableColumn {
|
||||
}
|
||||
}
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
pagination: Pagination;
|
||||
|
||||
results: Array<T>;
|
||||
}
|
||||
|
||||
export abstract class Table<T> extends AKElement implements TableLike {
|
||||
export abstract class Table<T> extends WithLicenseSummary(AKElement) implements TableLike {
|
||||
abstract apiEndpoint(): Promise<PaginatedResponse<T>>;
|
||||
abstract columns(): TableColumn[];
|
||||
abstract row(item: T): SlottedTemplateResult[];
|
||||
|
||||
private isLoading = false;
|
||||
|
||||
@property({ type: Boolean })
|
||||
supportsQL: boolean = false;
|
||||
|
||||
searchEnabled(): boolean {
|
||||
return false;
|
||||
}
|
||||
@ -181,6 +186,12 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
||||
PFDropdown,
|
||||
PFPagination,
|
||||
css`
|
||||
.pf-c-toolbar__group.pf-m-search-filter.ql {
|
||||
flex-grow: 1;
|
||||
}
|
||||
ak-table-search.ql {
|
||||
width: 100% !important;
|
||||
}
|
||||
.pf-c-table thead .pf-c-table__check {
|
||||
min-width: 3rem;
|
||||
}
|
||||
@ -288,7 +299,9 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
||||
return html`<tr role="row">
|
||||
<td role="cell" colspan="25">
|
||||
<div class="pf-l-bullseye">
|
||||
<ak-empty-state loading header=${msg("Loading")}></ak-empty-state>
|
||||
<ak-empty-state loading
|
||||
><span slot="header">${msg("Loading")}</span></ak-empty-state
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
</tr>`;
|
||||
@ -300,8 +313,9 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
||||
<td role="cell" colspan="8">
|
||||
<div class="pf-l-bullseye">
|
||||
${inner ??
|
||||
html`<ak-empty-state header="${msg("No objects found.")}"
|
||||
><div slot="primary">${this.renderObjectCreate()}</div>
|
||||
html`<ak-empty-state
|
||||
><span slot="header">${msg("No objects found.")}</span> >
|
||||
<div slot="primary">${this.renderObjectCreate()}</div>
|
||||
</ak-empty-state>`}
|
||||
</div>
|
||||
</td>
|
||||
@ -316,7 +330,8 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
||||
renderError(): SlottedTemplateResult {
|
||||
if (!this.error) return nothing;
|
||||
|
||||
return html`<ak-empty-state header="${msg("Failed to fetch objects.")}" icon="fa-ban">
|
||||
return html`<ak-empty-state icon="fa-ban"
|
||||
><span slot="header">${msg("Failed to fetch objects.")}</span>
|
||||
<div slot="body">${pluckErrorDetail(this.error)}</div>
|
||||
</ak-empty-state>`;
|
||||
}
|
||||
@ -470,14 +485,17 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
||||
});
|
||||
this.fetch();
|
||||
};
|
||||
|
||||
const isQL =
|
||||
this.supportsQL && this.licenseSummary?.status !== LicenseSummaryStatusEnum.Unlicensed;
|
||||
return !this.searchEnabled()
|
||||
? html``
|
||||
: html`<div class="pf-c-toolbar__group pf-m-search-filter">
|
||||
: html`<div class="pf-c-toolbar__group pf-m-search-filter ${isQL ? "ql" : ""}">
|
||||
<ak-table-search
|
||||
class="pf-c-toolbar__item pf-m-search-filter"
|
||||
?supportsQL=${this.supportsQL}
|
||||
class="pf-c-toolbar__item pf-m-search-filter ${isQL ? "ql" : ""}"
|
||||
value=${ifDefined(this.search)}
|
||||
.onSearch=${runSearch}
|
||||
.apiResponse=${this.data}
|
||||
>
|
||||
</ak-table-search>
|
||||
</div>`;
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { WithLicenseSummary } from "#elements/mixins/license";
|
||||
import "@goauthentik/components/ak-search-ql";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
@ -11,11 +14,19 @@ import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-gro
|
||||
import PFToolbar from "@patternfly/patternfly/components/Toolbar/toolbar.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
import { LicenseSummaryStatusEnum } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-table-search")
|
||||
export class TableSearch extends AKElement {
|
||||
export class TableSearch extends WithLicenseSummary(AKElement) {
|
||||
@property()
|
||||
value?: string;
|
||||
|
||||
@property({ type: Boolean })
|
||||
supportsQL: boolean = false;
|
||||
|
||||
@property({ attribute: false })
|
||||
apiResponse?: PaginatedResponse<unknown>;
|
||||
|
||||
@property()
|
||||
onSearch?: (value: string) => void;
|
||||
|
||||
@ -30,39 +41,63 @@ export class TableSearch extends AKElement {
|
||||
::-webkit-search-cancel-button {
|
||||
display: none;
|
||||
}
|
||||
ak-search-ql {
|
||||
width: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
renderInput(): TemplateResult {
|
||||
if (
|
||||
this.supportsQL &&
|
||||
this.licenseSummary?.status !== LicenseSummaryStatusEnum.Unlicensed
|
||||
) {
|
||||
return html`<ak-search-ql
|
||||
.apiResponse=${this.apiResponse}
|
||||
.value=${this.value}
|
||||
.onSearch=${(value: string) => {
|
||||
if (!this.onSearch) return;
|
||||
this.onSearch(value);
|
||||
}}
|
||||
name="search"
|
||||
></ak-search-ql>`;
|
||||
}
|
||||
return html`<input
|
||||
class="pf-c-form-control"
|
||||
name="search"
|
||||
type="search"
|
||||
placeholder=${msg("Search...")}
|
||||
value="${ifDefined(this.value)}"
|
||||
@search=${(ev: Event) => {
|
||||
if (!this.onSearch) return;
|
||||
this.onSearch((ev.target as HTMLInputElement).value);
|
||||
}}
|
||||
/>`;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
return html`<form
|
||||
class="pf-c-input-group"
|
||||
method="GET"
|
||||
method="get"
|
||||
@submit=${(e: Event) => {
|
||||
e.preventDefault();
|
||||
if (!this.onSearch) return;
|
||||
const el = this.shadowRoot?.querySelector<HTMLInputElement>("input[type=search]");
|
||||
const el = this.shadowRoot?.querySelector<HTMLInputElement | HTMLTextAreaElement>(
|
||||
"[name=search]",
|
||||
);
|
||||
if (!el) return;
|
||||
if (el.value === "") return;
|
||||
this.onSearch(el?.value);
|
||||
}}
|
||||
>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
name="search"
|
||||
type="search"
|
||||
placeholder=${msg("Search...")}
|
||||
value="${ifDefined(this.value)}"
|
||||
@search=${(ev: Event) => {
|
||||
if (!this.onSearch) return;
|
||||
this.onSearch((ev.target as HTMLInputElement).value);
|
||||
}}
|
||||
/>
|
||||
${this.renderInput()}
|
||||
<button
|
||||
class="pf-c-button pf-m-control"
|
||||
type="reset"
|
||||
@click=${() => {
|
||||
if (!this.onSearch) return;
|
||||
this.value = "";
|
||||
this.onSearch("");
|
||||
}}
|
||||
>
|
||||
|
@ -19,7 +19,11 @@ describe("ak-empty-state", () => {
|
||||
});
|
||||
|
||||
it("should render the default loader", async () => {
|
||||
render(html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`);
|
||||
render(
|
||||
html`<ak-empty-state loading
|
||||
><span slot="header">${msg("Loading")}</span>
|
||||
</ak-empty-state>`,
|
||||
);
|
||||
|
||||
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
|
||||
await expect(empty).toExist();
|
||||
@ -29,7 +33,11 @@ describe("ak-empty-state", () => {
|
||||
});
|
||||
|
||||
it("should handle standard boolean", async () => {
|
||||
render(html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`);
|
||||
render(
|
||||
html`<ak-empty-state loading
|
||||
><span slot="header">${msg("Loading")}</span>
|
||||
</ak-empty-state>`,
|
||||
);
|
||||
|
||||
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
|
||||
await expect(empty).toExist();
|
||||
@ -39,7 +47,11 @@ describe("ak-empty-state", () => {
|
||||
});
|
||||
|
||||
it("should render a static empty state", async () => {
|
||||
render(html`<ak-empty-state header=${msg("No messages found")}> </ak-empty-state>`);
|
||||
render(
|
||||
html`<ak-empty-state
|
||||
><span slot="header">${msg("No messages found")}</span>
|
||||
</ak-empty-state>`,
|
||||
);
|
||||
|
||||
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
|
||||
await expect(empty).toExist();
|
||||
@ -51,7 +63,8 @@ describe("ak-empty-state", () => {
|
||||
|
||||
it("should render a slotted message", async () => {
|
||||
render(
|
||||
html`<ak-empty-state header=${msg("No messages found")}>
|
||||
html`<ak-empty-state
|
||||
><span slot="header">${msg("No messages found")}</span>
|
||||
<p slot="body">Try again with a different filter</p>
|
||||
</ak-empty-state>`,
|
||||
);
|
||||
|
2
web/types/node.d.ts
vendored
2
web/types/node.d.ts
vendored
@ -14,7 +14,7 @@ declare module "module" {
|
||||
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
||||
* ```
|
||||
*/
|
||||
// eslint-disable-next-line no-var
|
||||
|
||||
var __dirname: string;
|
||||
}
|
||||
}
|
||||
|
@ -9245,6 +9245,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -7753,6 +7753,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9305,6 +9305,9 @@ Las vinculaciones a grupos o usuarios se comparan con el usuario del evento.</ta
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9874,6 +9874,9 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9857,6 +9857,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9213,6 +9213,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9117,6 +9117,9 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9540,6 +9540,9 @@ Powiązania z grupami/użytkownikami są sprawdzane względem użytkownika zdarz
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9549,4 +9549,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body></file></xliff>
|
||||
|
@ -9632,6 +9632,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9604,6 +9604,9 @@ Gruplara/kullanıcılara yapılan bağlamalar, etkinliğin kullanıcısına kar
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -6368,6 +6368,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
@ -9878,12 +9878,18 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf9686d31d28fcf7d">
|
||||
<source>Show field content</source>
|
||||
<target>显示字段内容</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sb1b05a7573ab618c">
|
||||
<source>Hide field content</source>
|
||||
<target>隐藏字段内容</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
<target>使用 Plex 重新验证身份</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -7453,6 +7453,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -3011,11 +3011,6 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
<source>Load servers</source>
|
||||
<target>加载服务器</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s24f405197ede5ebb">
|
||||
<source>Re-authenticate with plex</source>
|
||||
<target>使用 Plex 重新验证身份</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sc297b2e13c28ecf9">
|
||||
<source>Allow friends to authenticate via Plex, even if you don't share any servers</source>
|
||||
@ -9880,6 +9875,18 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<trans-unit id="sb3d5c0a0501669df">
|
||||
<source>Generate New Certificate-Key Pair</source>
|
||||
<target>生成新的证书密钥对</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf9686d31d28fcf7d">
|
||||
<source>Show field content</source>
|
||||
<target>显示字段内容</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sb1b05a7573ab618c">
|
||||
<source>Hide field content</source>
|
||||
<target>隐藏字段内容</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
<target>使用 Plex 重新验证身份</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9192,6 +9192,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4f820625804ed29b">
|
||||
<source>Re-authenticate with Plex</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0433d667ea6eec1a">
|
||||
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -70,9 +70,6 @@ To check if your config has been applied correctly, you can run the following co
|
||||
- `AUTHENTIK_POSTGRESQL__USER`: Database user
|
||||
- `AUTHENTIK_POSTGRESQL__PORT`: Database port, defaults to 5432
|
||||
- `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__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"`
|
||||
@ -85,7 +82,7 @@ To check if your config has been applied correctly, you can run the following co
|
||||
|
||||
The PostgreSQL settings `HOST`, `PORT`, `USER`, and `PASSWORD` support hot-reloading. Adding and removing read replicas doesn't support hot-reloading.
|
||||
|
||||
- `AUTHENTIK_POSTGRESQL__DEFAULT_SCHEMA`:ak-version[2024.12]
|
||||
- `AUTHENTIK_POSTGRESQL__DEFAULT_SCHEMA` :ak-version[2024.12]
|
||||
|
||||
The name of the schema used by default in the database. Defaults to `public`.
|
||||
|
||||
|
@ -142,6 +142,17 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2025.6
|
||||
- tenants: fix tenant aware celery scheduler (cherry-pick #14921)
|
||||
- web/user: fix user settings flow not loading (cherry-pick #14911) (#14930)
|
||||
|
||||
## Fixed in 2025.6.2
|
||||
|
||||
- brands: fix custom_css being escaped (cherry-pick #14994) (#14996)
|
||||
- core: bump django from 5.1.10 to 5.1.11 (cherry-pick #14997) (#15010)
|
||||
- core: bump django from 5.1.9 to 5.1.10 (cherry-pick #14951) (#15008)
|
||||
- internal/outpost: fix incorrect usage of golang SHA API (cherry-pick #14981) (#14982)
|
||||
- providers/rac: fixes prompt data not being merged with connection_settings (cherry-pick #15037) (#15038)
|
||||
- stages/email: Only attach logo to email if used (cherry-pick #14835) (#14969)
|
||||
- web/elements: fix dual select without sortBy (cherry-pick #14977) (#14979)
|
||||
- web/elements: fix typo in localeComparator (cherry-pick #15054) (#15055)
|
||||
|
||||
## API Changes
|
||||
|
||||
#### What's New
|
||||
|
@ -27,3 +27,29 @@ uv run ak create_recovery_key 10 akadmin
|
||||
```
|
||||
|
||||
This will output a link, that can be used to instantly gain access to authentik as the user specified above. The link is valid for amount of years specified above, in this case, 10 years.
|
||||
|
||||
## Can't access initial setup flow during installation steps
|
||||
|
||||
If you're unable to access the initial setup flow (`/if/flow/initial-setup/`) immediately after installing authentik, first try restarting the containers because this often resolves temporary issues.
|
||||
|
||||
However, if the issue persists after restarting, you can directly set the admin password using the following commands:
|
||||
|
||||
Docker Compose deployments:
|
||||
|
||||
```bash
|
||||
docker compose exec server ak changepassword akadmin
|
||||
```
|
||||
|
||||
Kubernetes deployments:
|
||||
|
||||
```bash
|
||||
kubectl exec -it deployment/authentik-server -c server -- ak changepassword akadmin
|
||||
```
|
||||
|
||||
After following the prompts to set a new password, you can then login via: `https://authentik.company/if/flow/default-authentication-flow/?next=%2F`
|
||||
|
||||
After logging in, you can set the email address and other settings for the account by navigating to **Directory** > **Users** and editing the user account.
|
||||
|
||||
:::note
|
||||
This method bypasses the initial setup flow and should only be used as a last resort. The initial setup flow is the recommended method to configure the administrator user.
|
||||
:::
|
||||
|
@ -49,7 +49,7 @@ After you are connected, execute these commands to create a database backup:
|
||||
cd /bitnami/postgresql/
|
||||
|
||||
# Set the PostgreSQL password from environment variable
|
||||
export PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD
|
||||
export PGPASSWORD=$(cat $POSTGRES_PASSWORD_FILE)
|
||||
|
||||
# Create a full database dump
|
||||
pg_dump -U $POSTGRES_USER $POSTGRES_DB > /bitnami/postgresql/dump.sql
|
||||
@ -117,7 +117,7 @@ cd /bitnami/postgresql/
|
||||
ls -lh dump.sql
|
||||
|
||||
# Set the PostgreSQL password
|
||||
export PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD
|
||||
export PGPASSWORD=$(cat $POSTGRES_PASSWORD_FILE)
|
||||
|
||||
# Import the database dump
|
||||
psql -U $POSTGRES_USER $POSTGRES_DB < dump.sql
|
||||
|
@ -161,6 +161,10 @@ Depending on your Nextcloud configuration, you may need to use `https://nextclou
|
||||
|
||||
- **Use unique user ID**: If this option is disabled, Nextcloud will use the mapped user ID as the Federated Cloud ID.
|
||||
|
||||
:::note
|
||||
If authentik and Nextcloud are running on the same host, you will need to add `'allow_local_remote_servers' => true` to your nextcloud `config.php` file. This setting allows remote servers with local addresses.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
To avoid a hashed Federated Cloud ID, deselect **Use unique user ID** and use `user_id` for the User ID mapping.
|
||||
:::
|
||||
|
@ -40,6 +40,7 @@ To support the integration of Zipline with authentik, you need to create an appl
|
||||
- Note the **Client ID** and **Client Secret** values because they will be required later.
|
||||
- Set a `Strict` redirect URI to `https://zipline.company/api/auth/oauth/oidc`.
|
||||
- Select any available signing key.
|
||||
- Under **Advanced Protocol Settings** > **Scopes**, add `authentik default OAuth Mapping: OpenID 'offline_access'` to the **Selected Scopes** list.
|
||||
- **Configure Bindings** _(optional)_: Create a [binding](/docs/add-secure-apps/flows-stages/bindings/) (policy, group, or user) to manage the listing and access to applications on a user's **My applications** page.
|
||||
|
||||
3. Click **Submit** to save the new application and provider.
|
||||
|
156
website/package-lock.json
generated
156
website/package-lock.json
generated
@ -22,7 +22,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"docusaurus-plugin-openapi-docs": "^4.4.0",
|
||||
"docusaurus-theme-openapi-docs": "^4.4.0",
|
||||
"postcss": "^8.5.5",
|
||||
"postcss": "^8.5.6",
|
||||
"prism-react-renderer": "^2.4.1",
|
||||
"react": "^18.3.1",
|
||||
"react-before-after-slider-component": "^1.1.8",
|
||||
@ -40,13 +40,13 @@
|
||||
"@goauthentik/prettier-config": "^1.0.5",
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/lodash": "^4.17.17",
|
||||
"@types/node": "^24.0.1",
|
||||
"@types/lodash": "^4.17.18",
|
||||
"@types/node": "^24.0.3",
|
||||
"@types/postman-collection": "^3.5.11",
|
||||
"@types/react": "^18.3.22",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
||||
"@typescript-eslint/parser": "^8.34.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.34.1",
|
||||
"@typescript-eslint/parser": "^8.34.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.29.0",
|
||||
"fast-glob": "^3.3.3",
|
||||
@ -54,7 +54,7 @@
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-packagejson": "^2.5.15",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.34.0"
|
||||
"typescript-eslint": "^8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.14.0"
|
||||
@ -6580,9 +6580,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.17.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz",
|
||||
"integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==",
|
||||
"version": "4.17.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.18.tgz",
|
||||
"integrity": "sha512-KJ65INaxqxmU6EoCiJmRPZC9H9RVWCRd349tXM2M3O5NA7cY6YL7c0bHAHQ93NOfTObEQ004kd2QVHs/r0+m4g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -6614,9 +6614,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.1.tgz",
|
||||
"integrity": "sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==",
|
||||
"version": "24.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz",
|
||||
"integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.8.0"
|
||||
@ -6830,17 +6830,17 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
|
||||
"integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
|
||||
"integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/type-utils": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/type-utils": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
@ -6854,7 +6854,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.34.0",
|
||||
"@typescript-eslint/parser": "^8.34.1",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
@ -6870,16 +6870,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
|
||||
"integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
|
||||
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -6895,14 +6895,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
|
||||
"integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
|
||||
"integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.34.0",
|
||||
"@typescript-eslint/types": "^8.34.0",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.34.1",
|
||||
"@typescript-eslint/types": "^8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -6917,14 +6917,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
|
||||
"integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
|
||||
"integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -6935,9 +6935,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
|
||||
"integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -6952,14 +6952,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
|
||||
"integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
@ -6976,9 +6976,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
|
||||
"integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
|
||||
"integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -6990,16 +6990,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
|
||||
"integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
|
||||
"integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.34.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"@typescript-eslint/project-service": "8.34.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -7019,9 +7019,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -7045,16 +7045,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
|
||||
"integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
|
||||
"integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.0"
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -7069,14 +7069,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
|
||||
"integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
|
||||
"integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -20672,9 +20672,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.5.tgz",
|
||||
"integrity": "sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==",
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@ -26387,15 +26387,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz",
|
||||
"integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
|
||||
"integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.34.0",
|
||||
"@typescript-eslint/parser": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.34.1",
|
||||
"@typescript-eslint/parser": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -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.5",
|
||||
"postcss": "^8.5.6",
|
||||
"prism-react-renderer": "^2.4.1",
|
||||
"react": "^18.3.1",
|
||||
"react-before-after-slider-component": "^1.1.8",
|
||||
@ -55,13 +55,13 @@
|
||||
"@goauthentik/prettier-config": "^1.0.5",
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/lodash": "^4.17.17",
|
||||
"@types/node": "^24.0.1",
|
||||
"@types/lodash": "^4.17.18",
|
||||
"@types/node": "^24.0.3",
|
||||
"@types/postman-collection": "^3.5.11",
|
||||
"@types/react": "^18.3.22",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
||||
"@typescript-eslint/parser": "^8.34.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.34.1",
|
||||
"@typescript-eslint/parser": "^8.34.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.29.0",
|
||||
"fast-glob": "^3.3.3",
|
||||
@ -69,7 +69,7 @@
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-packagejson": "^2.5.15",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.34.0"
|
||||
"typescript-eslint": "^8.34.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rspack/binding-darwin-arm64": "1.3.15",
|
||||
|
Reference in New Issue
Block a user