Skip to content

Conversation

@luca-peruzzo
Copy link
Member

@luca-peruzzo luca-peruzzo commented Nov 30, 2025

Thanks to @lekhmanrus for his contribution on this.

Summary by CodeRabbit

  • Bug Fixes

    • Error messages for missing pages now include the specific page ID for clearer troubleshooting.
  • Chores

    • Upgraded project and dev tooling to the next major framework release and updated formatting/linting and build configs.
    • CI workflow adjusted to run on feature branches.
    • TypeScript configuration updated.
  • Refactor

    • Many imports converted to type-only to streamline build output.
  • Removed

    • One Storybook story file and its associated exports were deleted.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 30, 2025

Walkthrough

Switched ESLint config to use defineConfig and added languageOptions; upgraded Angular/tooling and other deps to v21 and bumped package versions; added verbatimModuleSyntax in tsconfig and removed lib; converted many runtime imports to TypeScript type-only imports; minor reflows and a few message/CI/story removals.

Changes

Cohort / File(s) Summary
ESLint config
eslint.config.js, src/eslint.config.js
Replace tseslint.config(...) with defineConfig(...); add languageOptions (parser + projectService); add @typescript-eslint plugin; switch to explicit tseslint.configs.* extends; add @typescript-eslint/consistent-type-imports; simplify prettier/prettier rule; normalize HTML extends.
Package manifests
package.json, src/package.json
Bump project version to 21.0.0-rc.2; upgrade Angular packages and related tooling (Angular 21, angular-eslint, typescript-eslint, ng-packagr, Storybook, prettier, chokidar, keycloakify, zod, etc.).
TypeScript config
tsconfig.json
Remove lib entries; add verbatimModuleSyntax: true.
Account module — type-only imports
src/account/... (DefaultPage/DefaultPage.ts, classes/component-reference/component-reference.class.ts, directives/kc-class/kc-class.directive.ts, services/account-resource-injector/account-resource-injector.service.ts, template/template.component.ts)
Convert various imports (Type, ClassKey, DoCheck, EffectRef, Observable, Script) to type-only imports; minor dynamic-import formatting.
Login module — type-only imports & tweaks
src/login/... (defaultPage.ts, directives/kc-class/kc-class.directive.ts, components/*, pages/*, services/user-profile-form/user-profile-form.service.ts, template/template.component.ts)
Convert many imports to type-only (FormAction, FormFieldError, Signal, WritableSignal, TemplateRef, Type, OnDestroy, OnInit, AfterViewInit, etc.); reflow dynamic imports; defaultPage error includes pageId; replace CommonModule with NgClass in login component; minor DI/change-detection additions in stories.
Lib pipes & services — type-only imports
src/lib/pipes/*, src/lib/services/resource-injector/resource-injector.service.ts
Convert PipeTransform, SafeHtml/ResourceUrl/Script/Style/Url, Renderer2, Script to type-only imports across multiple pipe/service files.
Stories — type-only imports / removals / small edits
stories/**/* (many files)
Replace many Storybook/runtime imports with import type variants; add small formatting changes; remove stories/account/pages/KcPageStory.ts.
CI workflow
.github/workflows/ci.yaml
Update workflow triggers to run on feature/next branches for push and pull_request.
Miscellaneous formatting
assorted TS files
Small import reflows, blank-line additions, and minor message/content tweaks; no functional logic changes besides noted items.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • ESLint config changes (eslint.config.js, src/eslint.config.js) — parser/plugin wiring and new rules.
    • Dependency bumps (package.json, src/package.json) — verify compatibility and changelogs for Angular 21/tooling.
    • tsconfig.json verbatimModuleSyntax addition — ensure build/tooling (bundlers/packagers) handle it.
    • Deleted story file stories/account/pages/KcPageStory.ts — confirm intentional removal and update docs/tests.
    • Type-only import conversions in files that might have relied on runtime symbols (spot-check a few representative files).

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • kathari00

Poem

🐰 Hopped through code with nimble paws,

Types grew quiet, lint made laws.
Angular climbed a version tree,
Bunny cheered — imports set free! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: upgrading the Angular framework from version 20 to version 21, which is the primary objective of this changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/next

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/login/components/input-tag/input-tag.component.ts (1)

56-88: Fix fieldIndex signal handling and falsy index checks

  • fieldIndex is created via input<number | undefined>(), so this.fieldIndex is a signal function, and you should read it via this.fieldIndex().
  • In value, if (index) treats 0 as falsy, so the first element in an array is never returned.
  • In onChange, if (this.fieldIndex !== undefined) always passes (the function is never undefined); should check the signal value via fieldIndex() instead.
  • The template also has the same falsy check issue at line 10: [attr.aria-invalid]="index && displayableErrors()?.[index]" should use index != null.

This causes incorrect behavior for multi-valued attributes, especially when fieldIndex is 0.

Suggested fixes:

In value computed:

if (index != null) {
    return valueOrValues[index] ?? null;
}

In onChange:

const fieldIndex = this.fieldIndex();
if (fieldIndex != null && valueOrValues instanceof Array) {
    return valueOrValues.map((value, i) =>
        i === fieldIndex ? (event.target as HTMLInputElement)?.value : value
    );
}

In template line 10:

[attr.aria-invalid]="index != null && displayableErrors()?.[index] !== undefined"
src/account/DefaultPage/DefaultPage.ts (1)

60-65: Return type may be undefined for unhandled pageId values.

If pageId doesn't match any switch case, ComponentBootstrapPromise remains undefined, and the optional chaining ?.then() returns undefined. However, the function's return type is Promise<{...}> without accounting for this.

Consider either:

  1. Adding a default case that throws an error for unhandled page IDs
  2. Updating the return type to Promise<{...}> | undefined
         case 'federatedIdentity.ftl':
             ComponentBootstrapPromise =
                 import('@keycloakify/angular/account/pages/federatedIdentity').then(
                     c => c.FederatedIdentityComponent
                 );
             break;
+        default:
+            throw new Error(`Unhandled pageId: ${pageId}`);
     }
-    return ComponentBootstrapPromise?.then(ComponentBootstrap => ({
+    return ComponentBootstrapPromise.then(ComponentBootstrap => ({
         ComponentBootstrap,
         doMakeUserConfirmPassword: false,
         doUseDefaultCss,
         classes
     }));
🧹 Nitpick comments (1)
src/login/pages/saml-post-form/saml-post-form.component.ts (1)

50-61: Minor style suggestion: simplify the null-coalescing check.

Line 51 performs two separate null and undefined checks; you could simplify this to if (!this.htmlFormElement()) for brevity, since signal getters return a falsy value when unset.

-    if (this.htmlFormElement() === null || this.htmlFormElement() === undefined) {
+    if (!this.htmlFormElement()) {
         return;
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61d2b8b and 778d933.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (32)
  • eslint.config.js (2 hunks)
  • package.json (2 hunks)
  • src/account/DefaultPage/DefaultPage.ts (2 hunks)
  • src/account/classes/component-reference/component-reference.class.ts (1 hunks)
  • src/account/directives/kc-class/kc-class.directive.ts (1 hunks)
  • src/account/services/account-resource-injector/account-resource-injector.service.ts (1 hunks)
  • src/account/template/template.component.ts (2 hunks)
  • src/eslint.config.js (1 hunks)
  • src/lib/pipes/input-type/input-type.pipe.ts (1 hunks)
  • src/lib/pipes/is-array-with-empty-object/is-array-with-empty-object.pipe.ts (1 hunks)
  • src/lib/pipes/kc-sanitize/kc-sanitize.pipe.ts (1 hunks)
  • src/lib/pipes/to-array/to-array.pipe.ts (1 hunks)
  • src/lib/pipes/to-number/to-number.pipe.ts (1 hunks)
  • src/lib/services/resource-injector/resource-injector.service.ts (1 hunks)
  • src/login/components/input-field-by-type/input-field-by-type.component.ts (1 hunks)
  • src/login/components/input-tag-selects/input-tag-selects.component.ts (1 hunks)
  • src/login/components/input-tag/input-tag.component.ts (1 hunks)
  • src/login/components/password-wrapper/password-wrapper.component.ts (1 hunks)
  • src/login/components/user-profile-form-fields/user-profile-form-fields.component.ts (1 hunks)
  • src/login/defaultPage.ts (4 hunks)
  • src/login/directives/kc-class/kc-class.directive.ts (1 hunks)
  • src/login/pages/idp-review-user-profile/idp-review-user-profile.component.ts (1 hunks)
  • src/login/pages/login-recovery-authn-code-config/login-recovery-authn-code-config.component.ts (1 hunks)
  • src/login/pages/login-update-profile/login-update-profile.component.ts (1 hunks)
  • src/login/pages/login/login.component.ts (2 hunks)
  • src/login/pages/register/register.component.ts (1 hunks)
  • src/login/pages/saml-post-form/saml-post-form.component.ts (1 hunks)
  • src/login/pages/update-email/update-email.component.ts (1 hunks)
  • src/login/services/user-profile-form/user-profile-form.service.ts (2 hunks)
  • src/login/template/template.component.ts (2 hunks)
  • src/package.json (1 hunks)
  • tsconfig.json (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (35)
src/login/components/password-wrapper/password-wrapper.component.ts (1)

1-1: LGTM!

The type-only import of WritableSignal is correctly applied. Since WritableSignal is used only as a type annotation (line 36), converting it to a type-only import reduces runtime bundle size without affecting functionality. This aligns with the PR's systematic refactoring toward type-only imports and is compatible with Angular 21 and verbatimModuleSyntax: true.

src/login/components/input-tag-selects/input-tag-selects.component.ts (1)

1-1: Type-only import for Signal correctly applied.

The type Signal annotation on line 1 properly marks this import as type-only, which aligns with TypeScript's verbatimModuleSyntax: true requirement introduced in the Angular 21 upgrade. Since Signal is used exclusively as a type annotation on line 40 and never as a runtime value, this change is correct and follows best practices.

src/login/pages/saml-post-form/saml-post-form.component.ts (2)

1-10: Import refactoring aligns with Angular 21 and TypeScript strict mode.

The type-only import formatting correctly marks compile-time-only types (AfterViewInit, ElementRef, TemplateRef) while preserving runtime values. This matches the PR's shift toward stricter TypeScript settings with verbatimModuleSyntax: true.


20-49: Modern Angular patterns in place; component structure is sound.

Dependency injection with inject<T>(), the viewChild() signal API, and proper type generics all demonstrate contemporary Angular 21 patterns.

src/lib/pipes/is-array-with-empty-object/is-array-with-empty-object.pipe.ts (1)

1-13: Type-only import for PipeTransform is correct

The switch to a type-only import is consistent with verbatimModuleSyntax and does not affect runtime behavior. Pipe logic remains unchanged and looks good.

src/lib/services/resource-injector/resource-injector.service.ts (1)

1-50: Type-only imports for Renderer2 and Script look good

Converting Renderer2 and Script to type-only imports matches their usage (annotation-only) and is compatible with TS verbatimModuleSyntax. The observable-based injection logic is unchanged.

src/login/components/input-tag/input-tag.component.ts (1)

12-12: Type-only imports for FormAction / FormFieldError are appropriate

Both symbols are only used as types, so marking them as type-only imports is correct and keeps the runtime import surface minimal.

src/lib/pipes/input-type/input-type.pipe.ts (1)

1-13: InputTypePipe type-only import is fine

Using a type-only import for PipeTransform correctly reflects its usage and works well with stricter TS module settings. The pipe behavior (html5- prefix stripping with default 'text') is unchanged and looks good.

src/login/pages/login-recovery-authn-code-config/login-recovery-authn-code-config.component.ts (1)

1-171: Type-only AfterViewInit import matches its usage

AfterViewInit is only referenced in the implements clause, so importing it as a type is appropriate and keeps the runtime import surface minimal. The lifecycle hook implementation remains unchanged.

src/login/components/user-profile-form-fields/user-profile-form-fields.component.ts (1)

2-55: TemplateRef as a type-only import is appropriate

TemplateRef is only used for the beforeField/afterField property types, so marking it as a type-only import is correct and aligns with the rest of the PR’s import type cleanup.

src/login/pages/login/login.component.ts (1)

1-20: This change is correct and safe — no CommonModule directives are used in the template

The template has been modernized to use Angular's new control flow syntax (@if, @for, @let) instead of structural directives like *ngIf and *ngFor. The only ngClass usage is the property binding [ngClass], which is provided by the imported NgClass directive. The replacement of CommonModule with NgClass is appropriate and complete.

src/package.json (1)

5-9: Angular 21 and keycloakify peer dependency versions are correctly aligned

The peerDependencies in src/package.json correctly specify keycloakify ^11.13.0 and Angular 21.0.0. These versions match the root package.json devDependencies (keycloakify ^11.13.0 and Angular 21.0.1), which are compatible and align with the PR's Angular 21 upgrade goal. Keycloakify 11.13.0 is framework-agnostic and compatible with Angular 21.

tsconfig.json (1)

25-25: verbatimModuleSyntax aligns with your type-only imports/bundler setup

Enabling verbatimModuleSyntax here is consistent with the project-wide move to import type and moduleResolution: "bundler". No issues from this change on its own.

src/account/classes/component-reference/component-reference.class.ts (1)

1-6: Type-only ClassKey import is appropriate

ClassKey is used purely in type positions, so switching to import { type ClassKey } is correct and keeps the runtime bundle leaner.

src/login/components/input-field-by-type/input-field-by-type.component.ts (1)

10-10: Converting FormAction/FormFieldError to type-only imports is safe

Both are only used in generic type positions (input/output), so making them type-only imports correctly removes them from the emitted JS without changing behavior.

src/login/pages/idp-review-user-profile/idp-review-user-profile.component.ts (1)

2-2: Type-only TemplateRef/Type import matches their usage

TemplateRef and Type are only referenced in generic type parameters (viewChild<TemplateRef<...>>, input<Type<...>>()), so importing them as types is correct and has no runtime effect.

src/login/services/user-profile-form/user-profile-form.service.ts (1)

1-15: Type-only imports for OnDestroy, SafeHtml, and Observable are correct

These symbols are used only in type positions (implements OnDestroy, property types, and formState$: Observable<FormState>), while runtime values (DomSanitizer, BehaviorSubject, map) remain value imports, so this conversion is sound.

You can rely on ng build/ng lint to confirm there are no unexpected diagnostics from these type-only import changes.

src/lib/pipes/to-array/to-array.pipe.ts (1)

1-1: PipeTransform as a type-only import is appropriate

PipeTransform is only used in the implements clause, so importing it as a type while keeping Pipe as a value import is correct and has no runtime impact.

src/lib/pipes/to-number/to-number.pipe.ts (1)

1-1: Type-only PipeTransform import here is also correct

ToNumberPipe only uses PipeTransform in the implements clause, so making it a type-only import is consistent and leaves runtime behavior unchanged.

package.json (1)

29-61: Angular 21 / TypeScript / tooling versions are compatible

The devDependencies upgrades are well-aligned: Angular 21 requires TypeScript >=5.9 <6.0, and the pinned version typescript ~5.9.3 satisfies this. Similarly, typescript-eslint ^8.48.0 supports TypeScript 5.9.x, and ng-packagr ^21.0.0 explicitly supports Angular 21 with matching TS requirements. The major version numbers (Angular 21, angular-eslint 21, ng-packagr 21) are intentionally coordinated. No known incompatibilities exist between these specific versions.

src/login/pages/update-email/update-email.component.ts (1)

2-7: Type-only imports match pure type usage

TemplateRef, Type, and UserProfileFormFieldsComponent are only used in generic/type positions (viewChild and input<Type<...>>), so marking them as type imports is safe and aligns with stricter TS/ESLint settings.

src/login/pages/register/register.component.ts (1)

2-20: Lifecycle and component generics correctly converted to type-only imports

OnInit, OnDestroy, Type, and UserProfileFormFieldsComponent are only used as interfaces/generics (implements, input<Type<...>>), so switching them to type imports is correct and keeps runtime bundle lean.

src/login/pages/login-update-profile/login-update-profile.component.ts (1)

2-7: Type-only imports are consistent with usage

TemplateRef, Type, and UserProfileFormFieldsComponent are only referenced in type positions (viewChild and input<Type<...>>), so marking them as type imports is appropriate and behavior-preserving.

src/login/defaultPage.ts (1)

53-55: Dynamic imports unchanged; error message improved with pageId context

The dynamic imports remain semantically identical (same module paths and component symbols), and the updated default error now includes the pageId, which improves debugging without changing control flow.

Also applies to: 93-95, 125-127, 129-131, 145-147, 149-151, 153-153

src/login/template/template.component.ts (1)

2-18: EffectRef and KcContext safely switched to type-only imports

EffectRef is only used as a type annotation for #effectRef, and KcContext only as the generic parameter to inject<KcContext>. Their runtime counterparts aren’t referenced, so converting these imports to type preserves behavior and matches the type-import pattern elsewhere.

Also applies to: 25-25

src/eslint.config.js (1)

2-5: Confirm defineConfig(...rootConfig) matches the new root config shape

This now delegates to defineConfig instead of tseslint.config, but still spreads rootConfig. That’s fine only if rootConfig is an array of flat config fragments intended to be spread into defineConfig; if ../eslint.config.js was also updated to return a already-wrapped config, this may double-wrap or change behavior. Please verify ESLint still runs as expected with this file (e.g., run your lint script and check that TS rules and parser settings are applied as before).

src/login/directives/kc-class/kc-class.directive.ts (1)

3-15: DoCheck and ClassKey correctly converted to type-only imports

DoCheck is only used via implements DoCheck and ngDoCheck, and ClassKey appears solely in type aliases and generics. Marking both as type imports is safe and consistent with type-only import conventions.

src/lib/pipes/kc-sanitize/kc-sanitize.pipe.ts (1)

1-9: PipeTransform and Safe symbols used purely as types*

PipeTransform and the Safe* types are only referenced in the pipe’s implements clause and return type annotation; converting them to type imports is correct and leaves the runtime behavior (via DomSanitizer) untouched.

src/account/services/account-resource-injector/account-resource-injector.service.ts (1)

3-3: LGTM!

The type-only import for Script is correct since it's only used as a type annotation in the insertAdditionalScripts method signature at line 38. This aligns with the verbatimModuleSyntax: true compiler option and the new consistent-type-imports ESLint rule.

src/account/template/template.component.ts (2)

7-7: LGTM!

The type-only imports for EffectRef and Type from @angular/core are correct:

  • EffectRef is only used as a type annotation for the private field #effectRef
  • Type is only used as a generic type parameter in input<Type<unknown>>()

Also applies to: 12-12


26-27: LGTM!

The type-only imports for ClassKey and Observable are appropriate since both are only used in type positions (field type annotations and generic parameters).

src/account/DefaultPage/DefaultPage.ts (1)

1-3: LGTM!

The type-only imports for Type and ClassKey are correct since both are only used in type annotation positions (return type and parameter type).

src/account/directives/kc-class/kc-class.directive.ts (1)

5-5: LGTM!

The type-only imports are correct:

  • DoCheck is an interface used in the implements clause, which is erased at compile time
  • ClassKey is only used in type positions

Both align with verbatimModuleSyntax: true.

Also applies to: 13-13

eslint.config.js (2)

7-10: LGTM!

The migration to defineConfig from eslint/config is the correct approach for ESLint's flat config format. This provides better type checking and IDE support for the configuration.


33-40: Good addition enforcing type-only imports.

The consistent-type-imports rule with inline-type-imports fixStyle explains the pattern seen across the codebase changes (e.g., import { type Script } rather than import type { Script }). This ensures consistent enforcement going forward.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
stories/login/pages/login-otp.stories.ts (1)

22-28: Consider giving each OTP credential a unique id

All but the first credential share id: 'credential2', which is atypical for Keycloak credential IDs and may make this story less representative of real data.

You could, for example, adjust the IDs like:

-                    { id: 'credential2', userLabel: 'Device 3' },
-                    { id: 'credential2', userLabel: 'Device 4' },
-                    { id: 'credential2', userLabel: 'Device 5' },
-                    { id: 'credential2', userLabel: 'Device 6' }
+                    { id: 'credential3', userLabel: 'Device 3' },
+                    { id: 'credential4', userLabel: 'Device 4' },
+                    { id: 'credential5', userLabel: 'Device 5' },
+                    { id: 'credential6', userLabel: 'Device 6' }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed29f23 and c05ab95.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (53)
  • package.json (3 hunks)
  • stories/account/KcContextMock.ts (1 hunks)
  • stories/account/KcPage.ts (1 hunks)
  • stories/account/KcPageStory.ts (2 hunks)
  • stories/account/i18n.ts (1 hunks)
  • stories/account/pages/KcPageStory.ts (0 hunks)
  • stories/account/pages/account.stories.ts (1 hunks)
  • stories/account/pages/applications.stories.ts (1 hunks)
  • stories/account/pages/federated-identity.stories.ts (1 hunks)
  • stories/account/pages/log.stories.ts (1 hunks)
  • stories/account/pages/password.stories.ts (1 hunks)
  • stories/account/pages/sessions.stories.ts (1 hunks)
  • stories/account/pages/totp.stories.ts (1 hunks)
  • stories/login/KcContextMock.ts (1 hunks)
  • stories/login/KcPage.ts (1 hunks)
  • stories/login/KcPageStory.ts (2 hunks)
  • stories/login/i18n.ts (1 hunks)
  • stories/login/pages/code.stories.ts (1 hunks)
  • stories/login/pages/delete-account-confirm.stories.ts (1 hunks)
  • stories/login/pages/delete-credential.stories.ts (1 hunks)
  • stories/login/pages/error.stories.ts (1 hunks)
  • stories/login/pages/frontchannel-logout.stories.ts (1 hunks)
  • stories/login/pages/idp-review-user-profile.stories.ts (1 hunks)
  • stories/login/pages/info.stories.ts (1 hunks)
  • stories/login/pages/login-config-totp.stories.ts (1 hunks)
  • stories/login/pages/login-idp-link-confirm-override.stories.ts (1 hunks)
  • stories/login/pages/login-idp-link-confirm.stories.ts (1 hunks)
  • stories/login/pages/login-idp-link-email.stories.ts (1 hunks)
  • stories/login/pages/login-oauth-grant.stories.ts (1 hunks)
  • stories/login/pages/login-oauth2-device-verify-user-code.stories.ts (1 hunks)
  • stories/login/pages/login-otp.stories.ts (1 hunks)
  • stories/login/pages/login-page-expired.stories.ts (1 hunks)
  • stories/login/pages/login-passkeys-conditional-authenticate.stories.ts (1 hunks)
  • stories/login/pages/login-password.stories.ts (1 hunks)
  • stories/login/pages/login-recovery-authn-code-config.stories.ts (1 hunks)
  • stories/login/pages/login-recovery-authn-code-input.stories.ts (1 hunks)
  • stories/login/pages/login-reset-otp.stories.ts (1 hunks)
  • stories/login/pages/login-reset-password.stories.ts (1 hunks)
  • stories/login/pages/login-update-password.stories.ts (1 hunks)
  • stories/login/pages/login-update-profile.stories.ts (1 hunks)
  • stories/login/pages/login-username.stories.ts (1 hunks)
  • stories/login/pages/login-verify-email.stories.ts (1 hunks)
  • stories/login/pages/login-x509-info.stories.ts (1 hunks)
  • stories/login/pages/login.stories.ts (1 hunks)
  • stories/login/pages/logout-confirm.stories.ts (1 hunks)
  • stories/login/pages/register.stories.ts (1 hunks)
  • stories/login/pages/saml-post-form.stories.ts (1 hunks)
  • stories/login/pages/select-authenticator.stories.ts (1 hunks)
  • stories/login/pages/terms.stories.ts (1 hunks)
  • stories/login/pages/update-email.stories.ts (1 hunks)
  • stories/login/pages/webauthn-authenticate.stories.ts (1 hunks)
  • stories/login/pages/webauthn-error.stories.ts (1 hunks)
  • stories/login/pages/webauthn-register.stories.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • stories/account/pages/KcPageStory.ts
✅ Files skipped from review due to trivial changes (11)
  • stories/account/pages/log.stories.ts
  • stories/login/KcContextMock.ts
  • stories/account/KcContextMock.ts
  • stories/account/pages/account.stories.ts
  • stories/login/pages/frontchannel-logout.stories.ts
  • stories/login/pages/login-update-password.stories.ts
  • stories/login/pages/login-x509-info.stories.ts
  • stories/login/pages/login.stories.ts
  • stories/login/pages/delete-account-confirm.stories.ts
  • stories/login/pages/select-authenticator.stories.ts
  • stories/account/pages/federated-identity.stories.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🧬 Code graph analysis (2)
stories/account/KcPageStory.ts (2)
stories/account/KcPage.ts (1)
  • getKcPage (8-18)
stories/login/KcPage.ts (1)
  • getKcPage (10-22)
stories/login/KcPageStory.ts (1)
stories/login/KcPage.ts (1)
  • getKcPage (10-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (42)
stories/login/pages/login-oauth2-device-verify-user-code.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The conversion to import type is appropriate since Meta and StoryObj are only used in type positions (lines 4 and 13), not at runtime. This change aligns with TypeScript best practices and supports the verbatimModuleSyntax compiler option.

stories/login/pages/login-recovery-authn-code-input.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The conversion to import type is appropriate since Meta and StoryObj are used exclusively as types in this file (lines 4 and 14). This reduces the runtime bundle size and aligns with TypeScript best practices, especially when verbatimModuleSyntax is enabled.

stories/login/pages/login-passkeys-conditional-authenticate.stories.ts (1)

1-1: LGTM! Type-only import correctly applied.

The conversion to import type is appropriate since both Meta and StoryObj are exclusively used as type annotations. This aligns with the Angular 21 upgrade and verbatimModuleSyntax configuration changes.

stories/login/pages/login-reset-password.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The conversion to import type is appropriate since Meta and StoryObj are used exclusively in type positions. This aligns with TypeScript best practices and the verbatimModuleSyntax compiler option mentioned in the PR changes.

stories/login/pages/login-oauth-grant.stories.ts (1)

1-1: Type‑only import for Storybook types is appropriate here

Meta and StoryObj are only used as type parameters in this file, so converting to a import type keeps them out of the runtime bundle and aligns with stricter TS module settings. No further changes needed in this file.

Please just confirm that your TS config (especially module / verbatimModuleSyntax) is aligned across the repo so import type works consistently in all story files.

stories/login/pages/login-recovery-authn-code-config.stories.ts (1)

1-4: Type‑only Storybook imports look correct

Using import type for Meta and StoryObj is appropriate here since they’re only used in type positions (Meta<KcPageStory>, StoryObj<KcPageStory>). This should play nicely with stricter TS/Angular 21 module settings and avoids unnecessary runtime imports.

Please just confirm the TS/Storybook build passes so we know there are no other files relying on Meta/StoryObj as runtime values.

stories/login/pages/login-config-totp.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The conversion to a type-only import is appropriate since Meta and StoryObj are used exclusively as types. This reduces bundle size and aligns with the verbatimModuleSyntax compiler option mentioned in the PR.

stories/login/pages/webauthn-register.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The type-only import is correct as both symbols are used exclusively for type annotations. This change is consistent with the PR-wide migration pattern.

stories/login/pages/idp-review-user-profile.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The type-only import correctly reflects that Meta and StoryObj are used exclusively as types, improving type safety and bundle size.

stories/login/pages/code.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The type-only import is appropriate and aligns with the Angular 21 upgrade initiative to use modern TypeScript patterns.

stories/login/pages/login-username.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The change correctly uses type-only imports for symbols that are never used as runtime values, improving code quality.

stories/login/pages/login-update-profile.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The type-only import is correct and consistent with the broader refactoring pattern across the PR.

stories/login/pages/webauthn-authenticate.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The type-only import is appropriate for these Storybook types, ensuring they don't appear in the final JavaScript bundle.

stories/login/pages/webauthn-error.stories.ts (1)

1-1: LGTM! Correct use of type-only import.

The type-only import correctly ensures that Meta and StoryObj are used exclusively as types, completing the consistent migration pattern across all story files.

stories/login/pages/info.stories.ts (1)

1-1: LGTM! Type-only import is appropriate.

The conversion to import type is correct since Meta and StoryObj are only used as type annotations. This aligns with the PR's migration to type-only imports and works well with verbatimModuleSyntax.

stories/login/pages/delete-credential.stories.ts (1)

1-1: LGTM! Type-only import is appropriate.

stories/login/pages/login-reset-otp.stories.ts (1)

1-1: LGTM! Type-only import is appropriate.

stories/login/pages/logout-confirm.stories.ts (1)

1-1: LGTM! Type-only import is appropriate.

stories/login/pages/login-idp-link-confirm.stories.ts (1)

1-1: LGTM! Type-only import is appropriate.

stories/login/pages/login-idp-link-email.stories.ts (1)

1-1: LGTM! Type-only import is appropriate.

stories/login/pages/login-page-expired.stories.ts (1)

1-1: LGTM! Type-only import is appropriate.

stories/login/pages/register.stories.ts (1)

1-2: LGTM! Type-only imports are appropriate.

Both Meta/StoryObj and Attribute are correctly converted to type-only imports since they're only used for type annotations (satisfies on lines 67 and 103).

stories/login/pages/login-otp.stories.ts (1)

1-1: Type‑only Storybook import is appropriate

Meta and StoryObj are only used as types, so converting to import type is correct and keeps them out of the runtime bundle. Just ensure your TypeScript/Storybook build stays green after the Angular 21 upgrade.

stories/account/i18n.ts (1)

1-1: ThemeName as a type‑only import looks correct

ThemeName is only used in the generic for withThemeName, so switching to import type is appropriate and avoids an unnecessary runtime import.

stories/login/pages/login-verify-email.stories.ts (1)

1-1: Meta/StoryObj type‑only import matches Storybook usage

Meta and StoryObj are used purely for typing, so import type is the right choice and should not alter story behavior.

stories/login/pages/update-email.stories.ts (1)

1-1: Consistent use of type‑only Meta/StoryObj import

The move to import type aligns this story with the rest of the Storybook files and correctly reflects that Meta/StoryObj are compile‑time only.

stories/account/pages/sessions.stories.ts (1)

1-1: Type‑only Meta/StoryObj import is appropriate here

Meta and StoryObj are only used for typing the meta and Story alias, so converting them to a type‑only import is correct and avoids an unnecessary runtime dependency.

stories/login/pages/login-idp-link-confirm-override.stories.ts (1)

1-1: Storybook typings correctly moved to a type‑only import

Using import type for Meta and StoryObj matches their usage in this file and keeps the runtime surface minimal.

stories/login/i18n.ts (1)

1-1: ThemeName imported as a type fits the i18n builder usage

ThemeName is only used generically in withThemeName<ThemeName>(), so making it a type‑only import is appropriate and keeps runtime imports lean.

stories/account/KcPage.ts (1)

1-4: Type‑only imports for ClassKey, KcPage, and KcContext are well‑applied

ClassKey and KcContext are only used for typing, and KcPage is only referenced in the function return type, so moving them to type‑only imports is appropriate and keeps the runtime surface limited to getDefaultPageComponent and TemplateComponent.

stories/account/pages/password.stories.ts (1)

1-1: LGTM!

The type-only import is appropriate here since Meta and StoryObj are only used as type annotations, not as runtime values. This aligns with the verbatimModuleSyntax compiler option being added in this PR.

stories/account/pages/applications.stories.ts (1)

1-1: LGTM!

Correct use of type-only import for Meta and StoryObj which are only used as type annotations.

stories/login/pages/login-password.stories.ts (1)

1-1: LGTM!

Type-only import is correctly applied for symbols used only in type positions.

stories/login/pages/error.stories.ts (1)

1-1: LGTM!

Type-only import correctly reflects that Meta and StoryObj are used purely for type annotations.

stories/account/pages/totp.stories.ts (1)

1-1: LGTM!

Type-only import is appropriate for these Storybook types that are only used for type annotations.

stories/login/pages/saml-post-form.stories.ts (1)

1-1: LGTM! Correct type-only import.

Converting Meta and StoryObj to type-only imports reduces the runtime bundle size and follows TypeScript best practices, as these are only used for type annotations.

stories/account/KcPageStory.ts (2)

1-7: LGTM! Improved import declarations.

The expanded imports correctly use type-only imports for OnInit and Type, which are only used as type annotations. This reduces runtime dependencies and aligns with the TypeScript best practices in Angular 21.


43-47: Good practice: ensuring change detection after async operations.

Injecting ChangeDetectorRef and calling markForCheck() after the async getKcPage() resolves ensures the view updates correctly. This is defensive coding that works with both default and OnPush change detection strategies.

stories/login/pages/terms.stories.ts (1)

1-1: LGTM! Consistent type-only import pattern.

This change mirrors the pattern applied across other story files in the PR, correctly converting Meta and StoryObj to type-only imports.

stories/login/KcPageStory.ts (2)

1-11: LGTM! Proper import declarations and type-only usage.

The import changes correctly introduce ChangeDetectorRef and convert OnInit, Type, and StoryContext to type-only imports. This matches the pattern established in stories/account/KcPageStory.ts and maintains consistency across the codebase.


45-51: Correct change detection handling after async page load.

The addition of ChangeDetectorRef injection and the markForCheck() call ensures the component view updates after the asynchronous page component resolution. This mirrors the implementation in the account story component and follows Angular best practices for async operations.

stories/login/KcPage.ts (1)

1-6: LGTM! Precise type-only import usage.

The import changes correctly distinguish between type-only imports (ClassKey, KcPage, KcContext) and runtime imports (TemplateComponent). This is accurate because:

  • ClassKey, KcPage, and KcContext are only used in type positions
  • TemplateComponent is returned as a value (line 15) and requires a runtime import

These changes optimize the bundle and align with the broader type-import refinements across the PR.

@garronej
Copy link
Collaborator

Fantastic, thank you very much @luca-peruzzo!

(About everything else, I'm deep deep into a security rabithole but I'll claim back eventually)

@garronej garronej merged commit 171bd13 into main Nov 30, 2025
6 checks passed
@garronej garronej deleted the feature/next branch November 30, 2025 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants