Skip to content

web: Patternfly 5 Prep: Part 2#18085

Merged
BeryJu merged 15 commits intomainfrom
global-styles-fixes-v1
Nov 18, 2025
Merged

web: Patternfly 5 Prep: Part 2#18085
BeryJu merged 15 commits intomainfrom
global-styles-fixes-v1

Conversation

@GirlBossRush
Copy link
Contributor

@GirlBossRush GirlBossRush commented Nov 12, 2025

Details

This PR is a follow up on #17444, porting over additional dark theme styles from the base Patternfly 4 NPM package. In many situations, these default styles allow us to remove redundant rules within each custom element.

In some cases, we opt to adjust Patternfly's default values to find a balance between the current look and feel with the upcoming Patternfly 5 upgrade. This is mostly achieved with matching our custom colors with existing PF 4 values, using existing or newer values when we drift too far from PF 5 baseline.

@GirlBossRush GirlBossRush added the area:frontend Features or issues related to the browser, TypeScript, Node.js, etc label Nov 12, 2025
@GirlBossRush GirlBossRush requested a review from a team as a code owner November 12, 2025 06:37
@netlify
Copy link

netlify bot commented Nov 12, 2025

Deploy Preview for authentik-docs canceled.

Name Link
🔨 Latest commit 452da3b
🔍 Latest deploy log https://app.netlify.com/projects/authentik-docs/deploys/691c78e67485ba00081054c9

@netlify
Copy link

netlify bot commented Nov 12, 2025

Deploy Preview for authentik-storybook failed. Why did it fail? →

Name Link
🔨 Latest commit 452da3b
🔍 Latest deploy log https://app.netlify.com/projects/authentik-storybook/deploys/691c78e6f074e00008ac4d0c

@netlify
Copy link

netlify bot commented Nov 12, 2025

Deploy Preview for authentik-integrations canceled.

Name Link
🔨 Latest commit 452da3b
🔍 Latest deploy log https://app.netlify.com/projects/authentik-integrations/deploys/691c78e670b5dc0008b36529

@GirlBossRush GirlBossRush requested review from BeryJu and removed request for fheisler November 12, 2025 06:37
@codecov
Copy link

codecov bot commented Nov 12, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
2202 1 2201 2
View the top 1 failed test(s) by shortest run time
tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit::test_authorization_consent_implied
Stack Traces | 17.9s run time
self = <unittest.case._Outcome object at 0x7f039af96690>
test_case = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
subTest = False

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, subTest=False):
        old_success = self.success
        self.success = True
        try:
>           yield

.../hostedtoolcache/Python/3.13.9............/x64/lib/python3.13/unittest/case.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
result = <TestCaseFunction test_authorization_consent_implied>

    def run(self, result=None):
        if result is None:
            result = self.defaultTestResult()
            startTestRun = getattr(result, 'startTestRun', None)
            stopTestRun = getattr(result, 'stopTestRun', None)
            if startTestRun is not None:
                startTestRun()
        else:
            stopTestRun = None
    
        result.startTest(self)
        try:
            testMethod = getattr(self, self._testMethodName)
            if (getattr(self.__class__, "__unittest_skip__", False) or
                getattr(testMethod, "__unittest_skip__", False)):
                # If the class or method was skipped.
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                _addSkip(result, self, skip_why)
                return result
    
            expecting_failure = (
                getattr(self, "__unittest_expecting_failure__", False) or
                getattr(testMethod, "__unittest_expecting_failure__", False)
            )
            outcome = _Outcome(result)
            start_time = time.perf_counter()
            try:
                self._outcome = outcome
    
                with outcome.testPartExecutor(self):
                    self._callSetUp()
                if outcome.success:
                    outcome.expecting_failure = expecting_failure
                    with outcome.testPartExecutor(self):
>                       self._callTestMethod(testMethod)

.../hostedtoolcache/Python/3.13.9............/x64/lib/python3.13/unittest/case.py:651: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
method = <bound method TestProviderOAuth2OIDCImplicit.test_authorization_consent_implied of <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>>

    def _callTestMethod(self, method):
>       if method() is not None:

.../hostedtoolcache/Python/3.13.9............/x64/lib/python3.13/unittest/case.py:606: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
args = (), kwargs = {}

    @wraps(func)
    def wrapper(self: TransactionTestCase, *args, **kwargs):
        """Run test again if we're below max_retries, including tearDown and
        setUp. Otherwise raise the error"""
        nonlocal count
        try:
>           return func(self, *args, **kwargs)

tests/e2e/utils.py:461: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>,)
kwargs = {}, file = 'default/flow-default-invalidation-flow.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Invalidation flow\nentries:\n- attrs:\n    designation: invalidation\n    na...0\n    stage: !KeyOf default-invalidation-logout\n    target: !KeyOf flow\n  model: authentik_flows.flowstagebinding\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>,)
kwargs = {}
file = 'default/flow-default-provider-authorization-implicit-consent.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Provider authorization flow (implicit consent)\nentries:\n- attrs:\n    desi...henticated\n  identifiers:\n    slug: default-provider-authorization-implicit-consent\n  model: authentik_flows.flow\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>,)
kwargs = {}, file = 'system/providers-oauth2.yaml'
content = 'version: 1\nmetadata:\n  labels:\n    blueprints.goauthentik.io/system: "true"\n  name: System - OAuth2 Provider - Sc... application the ability to access the authentik API\n        # on behalf of the authorizing user\n        return {}\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>,)
kwargs = {}, config = <AuthentikCryptoConfig: authentik_crypto>

    @wraps(func)
    def wrapper(*args, **kwargs):
        config = apps.get_app_config(app_name)
        if isinstance(config, ManagedAppConfig):
            config._on_startup_callback(None)
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>

    @retry()
    @apply_blueprint(
        "default/flow-default-authentication-flow.yaml",
        "default/flow-default-invalidation-flow.yaml",
    )
    @apply_blueprint("default/flow-default-provider-authorization-implicit-consent.yaml")
    @apply_blueprint("system/providers-oauth2.yaml")
    @reconcile_app("authentik_crypto")
    def test_authorization_consent_implied(self):
        """test OpenID Provider flow (default authorization flow with implied consent)"""
        sleep(1)
        # Bootstrap all needed objects
        authorization_flow = Flow.objects.get(
            slug="default-provider-authorization-implicit-consent"
        )
        provider = OAuth2Provider.objects.create(
            name=self.application_slug,
            client_type=ClientTypes.CONFIDENTIAL,
            client_id=self.client_id,
            client_secret=self.client_secret,
            signing_key=create_test_cert(),
            redirect_uris=[
                RedirectURI(RedirectURIMatchingMode.STRICT, "http://localhost:9009/implicit/")
            ],
            authorization_flow=authorization_flow,
        )
        provider.property_mappings.set(
            ScopeMapping.objects.filter(
                scope_name__in=[
                    SCOPE_OPENID,
                    SCOPE_OPENID_EMAIL,
                    SCOPE_OPENID_PROFILE,
                    SCOPE_OFFLINE_ACCESS,
                ]
            )
        )
        provider.save()
        Application.objects.create(
            name=self.application_slug,
            slug=self.application_slug,
            provider=provider,
        )
        self.setup_client()
    
        self.driver.get("http://localhost:9009/implicit/")
        self.wait.until(ec.title_contains("authentik"))
        self.login()
    
>       body = self.parse_json_content()

tests/e2e/test_provider_oidc_implicit.py:153: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
context = <selenium.webdriver.remote.webelement.WebElement (session="118fb2a50ee14dbfca38a3003e3a6b19", element="f.DAC7E877B8B82A32EE1DF7A639E7226A.d.CD2B591A5AD8E024A9D104B4013CB0DD.e.29")>
timeout = 10

    def parse_json_content(
        self, context: WebElement | None = None, timeout: float | None = 10
    ) -> JSONType:
        """
        Parse JSON from a Selenium element's text content.
    
        If `context` is not provided, defaults to the <body> element.
        Raises a clear test failure if the element isn't found, the text doesn't appear
        within `timeout` seconds, or the text is not valid JSON.
        """
    
        try:
            if context is None:
                context = self.driver.find_element(By.TAG_NAME, "body")
        except NoSuchElementException:
            self.fail(
                f"No element found (defaulted to <body>). Current URL: {self.driver.current_url}"
            )
    
        wait_timeout = timeout or self.wait_timeout
        wait = WebDriverWait(context, wait_timeout)
    
        try:
            wait.until(lambda d: len(d.text.strip()) != 0)
        except TimeoutException:
            snippet = context.text.strip()[:500].replace("\n", " ")
            self.fail(
                f"Timed out waiting for element text to appear at {self.driver.current_url}. "
                f"Current content: {snippet or '<empty>'}"
            )
    
        body_text = context.text.strip()
        inner_html = context.get_attribute("innerHTML") or ""
    
        if "redirecting" in inner_html.lower():
            try:
                wait.until(lambda d: "redirecting" not in d.get_attribute("innerHTML").lower())
            except TimeoutException:
                snippet = context.text.strip()[:500].replace("\n", " ")
                inner_html = context.get_attribute("innerHTML") or ""
    
                self.fail(
                    f"Timed out waiting for redirect to finish at {self.driver.current_url}. "
                    f"Current content: {snippet or '<empty>'}"
                    f"{inner_html or '<empty>'}"
                )
    
            inner_html = context.get_attribute("innerHTML") or ""
            body_text = context.text.strip()
    
        snippet = body_text[:500].replace("\n", " ")
    
        if not body_text.startswith("{") and not body_text.startswith("["):
>           self.fail(
                f"Expected JSON content but got non-JSON text at {self.driver.current_url}: "
                f"{snippet or '<empty>'}"
                f"{inner_html or '<empty>'}"
            )

tests/e2e/utils.py:293: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
msg = 'Expected JSON content but got non-JSON text at http://10.1.0.148:.../if/flow/default-authentication-flow/?next=%2Fa...         </div>\n            </div>\n        </div>\n    \n<!----></ak-locale-context>\n\n        \n        \n    \n\n'

    def fail(self, msg=None):
        """Fail immediately, with the given message."""
>       raise self.failureException(msg)
E       AssertionError: Expected JSON content but got non-JSON text at http://10.1.0.148:.../if/flow/default-authentication-flow/?next=%2Fapplication%2Fo%2Fauthorize%2F%3Fclient_id%3Du2s4QkBSxb8Nk6jpuUqXgh9p2fATlrrPxBYVDLna%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A9009%252Fimplicit%252F%26response_type%3Did_token%2520token%26scope%3Dopenid%2520%2520profile%2520email%26state%3D2f6f224041e84814b3443e88be0d9fcf%26nonce%3Dd8e60c09b211468a898cec4372da3c40: Welcome to authentik! Pt5FBGEELDCeYtrGfZmU Not you? Password Form actions Continue Powered by authentik
E               
E       <ak-skip-to-content></ak-skip-to-content>
E       <ak-message-container theme="light"></ak-message-container>
E       
E       <ak-locale-context theme="light">
E           <div class="pf-c-page__drawer">
E               <div class="pf-c-drawer pf-m-collapsed" id="flow-drawer">
E                   <div class="pf-c-drawer__main">
E                       <div class="pf-c-drawer__content">
E                           <div class="pf-c-drawer__body">
E                                   <ak-flow-executor slug="default-authentication-flow" class="pf-c-login" data-layout="stacked" data-test-id="interface-root" theme="light">
E                                       
E       
E       <div class="ak-c-placeholder" id="ak-placeholder" slot="placeholder">
E           <span class="pf-c-spinner" role="progressbar" aria-valuetext="Loading...">
E               <span class="pf-c-spinner__clipper"></span>
E               <span class="pf-c-spinner__lead-ball"></span>
E               <span class="pf-c-spinner__tail-ball"></span>
E           </span>
E       </div>
E       
E       
E                                       <ak-brand-links slot="footer" exportparts="list:brand-links-list, list-item:brand-links-list-item" role="contentinfo" aria-label="Site footer" class="pf-c-login__footer pf-m-dark" theme="light"></ak-brand-links>
E                                   </ak-flow-executor>
E                               </div>
E                           </div>
E       
E                           <ak-flow-inspector id="flow-inspector" data-registration="lazy" class="pf-c-drawer__panel pf-m-width-33" slug="default-authentication-flow"></ak-flow-inspector>
E                       </div>
E                   </div>
E               </div>
E           
E       <!----></ak-locale-context>

.../hostedtoolcache/Python/3.13.9............/x64/lib/python3.13/unittest/case.py:732: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 12, 2025

authentik PR Installation instructions

Instructions for docker-compose

Add the following block to your .env file:

AUTHENTIK_IMAGE=ghcr.io/goauthentik/dev-server
AUTHENTIK_TAG=gh-452da3b1e7d92567117abf5c7b21d4babfa2dbca
AUTHENTIK_OUTPOSTS__CONTAINER_IMAGE_BASE=ghcr.io/goauthentik/dev-%(type)s:gh-%(build_hash)s

Afterwards, run the upgrade commands from the latest release notes.

Instructions for Kubernetes

Add the following block to your values.yml file:

authentik:
    outposts:
        container_image_base: ghcr.io/goauthentik/dev-%(type)s:gh-%(build_hash)s
global:
    image:
        repository: ghcr.io/goauthentik/dev-server
        tag: gh-452da3b1e7d92567117abf5c7b21d4babfa2dbca

Afterwards, run the upgrade commands from the latest release notes.

@GirlBossRush GirlBossRush force-pushed the global-styles-fixes-v1 branch 2 times, most recently from 5dacbc9 to d4ef5c3 Compare November 14, 2025 01:18
@GirlBossRush GirlBossRush requested a review from a team as a code owner November 14, 2025 01:18
@GirlBossRush GirlBossRush force-pushed the global-styles-fixes-v1 branch 2 times, most recently from 0436a60 to 8c0818a Compare November 17, 2025 15:13
@GirlBossRush GirlBossRush force-pushed the global-styles-fixes-v1 branch from 7e5d618 to b50f37b Compare November 17, 2025 23:16
GirlBossRush and others added 2 commits November 18, 2025 01:10
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
@github-project-automation github-project-automation bot moved this from Todo to In Progress in authentik Core Nov 18, 2025
@BeryJu BeryJu merged commit 5451e04 into main Nov 18, 2025
168 of 178 checks passed
@BeryJu BeryJu deleted the global-styles-fixes-v1 branch November 18, 2025 16:12
@github-project-automation github-project-automation bot moved this from In Progress to Done in authentik Core Nov 18, 2025
kensternberg-authentik added a commit that referenced this pull request Dec 11, 2025
* main: (55 commits)
  Makefile: Fix kerberos tests for brew users (#17223)
  website/docs: add 2025.8.5 and 2025.10.2 release notes (#18268)
  internal: Automated internal backport: 5000-sidebar.sec.patch to authentik-main (#18266)
  internal: Automated internal backport: 1498-oauth2-cc-user-active.sec.patch to authentik-main (#18265)
  internal: Automated internal backport: 1487-invitation-expiry.sec.patch to authentik-main (#18264)
  core, web: update translations (#18241)
  web: bump ts-pattern from 5.8.0 to 5.9.0 in /web (#18247)
  web: bump the react group across 2 directories with 1 update (#18244)
  web: bump knip from 5.66.2 to 5.70.0 in /web (#18245)
  core: bump library/nginx from `b5b9e01` to `553f64a` in /website (#18253)
  core: bump library/golang from `27e1c92` to `728cbef` (#18252)
  core: bump goauthentik/fips-debian from `65a9f1f` to `55c1514` (#18251)
  web: Bump Vitest, TypeScript config (#18238)
  web: bump js-yaml from 4.1.0 to 4.1.1 in /packages/esbuild-plugin-live-reload (#18237)
  web/i18n: Remove English Locale (#18164)
  web: bump js-yaml from 3.14.1 to 3.14.2 in /packages/docusaurus-config (#18239)
  web/i18n: Clean up locale scripts (#18163)
  stages/prompt: fix choices with labels causing error on submit (#18183)
  web: Patternfly 5 Prep: Part 2 (#18085)
  lifecycle/aws: bump aws-cdk from 2.1031.2 to 2.1032.0 in /lifecycle/aws (#18218)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:frontend Features or issues related to the browser, TypeScript, Node.js, etc

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants