Skip to content

Show user onboarding wizard based on claim, and give option to re-access it#9669

Open
savindi7 wants to merge 7 commits intowso2:masterfrom
savindi7:fixes-ui-onboarding
Open

Show user onboarding wizard based on claim, and give option to re-access it#9669
savindi7 wants to merge 7 commits intowso2:masterfrom
savindi7:fixes-ui-onboarding

Conversation

@savindi7
Copy link
Contributor

Purpose

  • Show the onboarding wizard based on userUserOnboardingWizard claim.
  • Add FAB in Home and Applications listing pages to re-access onboarding wizard

Related Issues

  • N/A

Related PRs

  • N/A

Checklist

  • e2e cypress tests locally verified. (for internal contributers)
  • Manual test round performed and verified.
  • UX/UI review done on the final implementation.
  • Documentation provided. (Add links if there are any)
  • Relevant backend changes deployed and verified
  • Unit tests provided. (Add links if there are any)
  • Integration tests provided. (Add links if there are any)

Security checks

Developer Checklist (Mandatory)

  • Complete the Developer Checklist in the related product-is issue to track any behavioral change or migration impact.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces local/app-list gating with a server-driven SCIM claim for onboarding visibility, removes select governance/login scopes, adds an Onboarding FAB (component, hook, and public export) across admin pages, makes onboarding callbacks async, and adds eligibility checks (account/org type, feature flag, scopes).

Changes

Cohort / File(s) Summary
Scope Configuration
apps/console/src/public/deployment.config.json
Removed internal_governance_update from onboarding.scopes.create and removed console:loginAndRegistration from onboarding.scopes.feature; branding scope retained.
Workspace Dependencies
features/admin.applications.v1/package.json, features/admin.home.v1/package.json
Added workspace dependency @wso2is/admin.onboarding.v1.
Page Integrations
features/admin.applications.v1/pages/applications.tsx, features/admin.home.v1/pages/home-page.tsx
Imported and rendered OnboardingFab on Applications and Home pages.
Public API Export
features/admin.onboarding.v1/public-api.ts
Exported OnboardingFab from onboarding public API.
FAB Component & IDs
features/admin.onboarding.v1/components/shared/onboarding-fab.tsx, features/admin.onboarding.v1/constants/component-ids.ts
Added OnboardingFab component (styled FAB with animations, navigates with source param) and FAB component ID.
FAB Visibility Hook
features/admin.onboarding.v1/hooks/use-onboarding-fab-visibility.ts
New hook computing FAB visibility from feature flag, user account type, organization type, and required create scopes.
Onboarding Status Hook
features/admin.onboarding.v1/hooks/use-onboarding-status.ts
Refactored to server-driven flow using SCIM claim check; removed local/app-list gating; markOnboardingComplete now returns Promise<void>.
Onboarding API
features/admin.onboarding.v1/api/get-onboarding-claim.ts, features/admin.onboarding.v1/api/update-onboarding-claim.ts
Added getOnboardingWizardClaim to read showOnboardingWizard SCIM claim and dismissOnboardingWizardClaim to PATCH it false.
Wizard & Steps
features/admin.onboarding.v1/components/onboarding-wizard.tsx, features/admin.onboarding.v1/components/steps/welcome-step.tsx
Made onComplete and onSkip async (Promise<void>), added optional isReturningUser prop and propagated it to WelcomeStep to adjust header text.
Onboarding Page
features/admin.onboarding.v1/pages/onboarding-page.tsx
Added intentional-access tracking (source=fab), feature/scope route guards, async handleComplete/handleSkip that await claim update, and pass isReturningUser to the wizard.
Changeset
.changeset/pretty-waves-march.md
Added changeset covering multiple packages for the onboarding update.

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description covers the Purpose section well, but all checklist items are unchecked and no supporting documentation, test links, or verification details are provided. Mark completed checklist items with checkboxes, provide links to unit/integration tests if available, and confirm security checks have been performed.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main changes: showing the onboarding wizard based on a claim and enabling re-access via a FAB component.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Changeset Required ✅ Passed Pull request includes valid changeset file (.changeset/pretty-waves-march.md) documenting all changed packages with appropriate patch version updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
Contributor

@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: 5

Caution

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

⚠️ Outside diff range comments (1)
features/admin.onboarding.v1/components/onboarding-wizard.tsx (1)

403-408: ⚠️ Potential issue | 🟠 Major

Handle rejected onComplete/onSkip promises with user feedback.

Both awaited callbacks can reject and currently have no local error handling, which can result in silent failures.

🛠️ Proposed fix
     const handleNext: () => Promise<void> = useCallback(async (): Promise<void> => {
         const nextStep: OnboardingStep = getNextStep(currentStep, onboardingData);

         if (currentStep === OnboardingStep.SUCCESS) {
-            await onComplete(onboardingData);
+            try {
+                await onComplete(onboardingData);
+            } catch (error: unknown) {
+                const errorMessage: string = error instanceof Error
+                    ? error.message
+                    : "Failed to complete onboarding. Please try again.";
+
+                dispatch(addAlert({
+                    description: errorMessage,
+                    level: AlertLevels.ERROR,
+                    message: "Onboarding Completion Failed"
+                }));
+            }
+
+            return;
         } else if (
             currentStep === OnboardingStep.DESIGN_LOGIN ||
             (currentStep === OnboardingStep.SELECT_APPLICATION_TEMPLATE && isM2M)
         ) {
             setDirection("forward");
             await createApplication();
         } else {
             setDirection("forward");
             setCurrentStep(nextStep);
         }
-    }, [ currentStep, onboardingData, isM2M, createApplication, onComplete ]);
+    }, [ currentStep, onboardingData, isM2M, createApplication, onComplete, dispatch ]);

     const handleSkip: () => Promise<void> = useCallback(async (): Promise<void> => {
-        await onSkip();
-    }, [ onSkip ]);
+        try {
+            await onSkip();
+        } catch (error: unknown) {
+            const errorMessage: string = error instanceof Error
+                ? error.message
+                : "Failed to skip onboarding. Please try again.";
+
+            dispatch(addAlert({
+                description: errorMessage,
+                level: AlertLevels.ERROR,
+                message: "Skip Failed"
+            }));
+        }
+    }, [ onSkip, dispatch ]);

As per coding guidelines "Dispatch error notifications via Redux with dispatch(addAlert({ description, level: AlertLevels.ERROR, message })) in catch blocks."

Also applies to: 430-432

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@features/admin.onboarding.v1/components/onboarding-wizard.tsx` around lines
403 - 408, The awaited calls to onComplete and onSkip in handleNext (the async
callback defined as handleNext) can reject and currently lack error handling;
wrap each await (the onComplete(onboardingData) branch and the onSkip() branch)
in try/catch blocks and in the catch dispatch an error alert using
dispatch(addAlert({ description: err?.message || String(err), level:
AlertLevels.ERROR, message: 'Onboarding error' })); ensure dispatch and
AlertLevels are imported/available in this component and do not swallow errors
silently (return/exit the handler after dispatching the alert as appropriate).
🧹 Nitpick comments (1)
features/admin.onboarding.v1/pages/onboarding-page.tsx (1)

89-89: Use the standard feature-status helper for onboarding enablement checks.

Line 89 uses a raw boolean read; switching to isFeatureEnabled(...) keeps this consistent with feature status handling conventions.

♻️ Suggested refactor
-import { useRequiredScopes } from "@wso2is/access-control";
+import { isFeatureEnabled, useRequiredScopes } from "@wso2is/access-control";
@@
-    const isFeatureEnabled: boolean = !!featureConfig?.onboarding?.enabled;
+    const isOnboardingFeatureEnabled: boolean = isFeatureEnabled(featureConfig, "onboarding");
@@
-        if (!isFeatureEnabled || !hasRequiredCreateScopes) {
+        if (!isOnboardingFeatureEnabled || !hasRequiredCreateScopes) {
             history.push(AppConstants.getAppHomePath());
@@
-    }, [ isLoading, isFeatureEnabled, shouldShowOnboarding, hasRequiredCreateScopes, isIntentionalAccess ]);
+    }, [ isLoading, isOnboardingFeatureEnabled, shouldShowOnboarding, hasRequiredCreateScopes, isIntentionalAccess ]);
@@
-    if (!isFeatureEnabled || !hasRequiredCreateScopes) {
+    if (!isOnboardingFeatureEnabled || !hasRequiredCreateScopes) {
         return null;
     }

As per coding guidelines, use isFeatureEnabled from @wso2is/access-control to evaluate feature enablement.

Also applies to: 98-99, 107-107, 133-135

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@features/admin.onboarding.v1/pages/onboarding-page.tsx` at line 89, Replace
the raw boolean checks against featureConfig?.onboarding?.enabled with the
central helper from `@wso2is/access-control`: import isFeatureEnabled and call it
to evaluate onboarding enablement (e.g., const onboardingEnabled =
isFeatureEnabled(featureConfig, "onboarding")), update all usages that currently
read featureConfig?.onboarding?.enabled (and avoid shadowing the imported name
by renaming the local variable from isFeatureEnabled to onboardingEnabled), and
use onboardingEnabled wherever the file currently performs the raw checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@features/admin.onboarding.v1/api/get-onboarding-claim.ts`:
- Around line 61-62: The current boolean expression using
!systemSchemaData?.[SHOW_ONBOARDING_WIZARD_ATTRIBUTE] incorrectly treats false
as true; update the claim evaluation so the onboarding wizard is considered
visible only when the stored attribute is not explicitly false. Replace the
expression in the get-onboarding-claim logic that references systemSchemaData
and SHOW_ONBOARDING_WIZARD_ATTRIBUTE with an explicit check such as
systemSchemaData?.[SHOW_ONBOARDING_WIZARD_ATTRIBUTE] !== false (or equivalent)
so false correctly resolves to hiding the wizard.

In `@features/admin.onboarding.v1/components/shared/onboarding-fab.tsx`:
- Around line 110-112: Replace the hardcoded "Setup Guide" label inside the
StyledFab (next to Rocket) with an i18next translation lookup; import and call
useTranslation from react-i18next in the component (e.g., const { t } =
useTranslation()) and render t('<namespace>:<key.path>') instead of the literal
string (for example t('admin:onboarding.setupGuide')); ensure the chosen key
follows the <namespace>:<key.path> format and that the translation entry is
added to your locale files.
- Around line 55-67: The pulseGlow keyframes currently hardcode box-shadow
colors and geometry; update the animation to use theme tokens instead: replace
hardcoded rgba(...) color with the appropriate theme color token (e.g.,
theme.colors.primary or theme.colors.accent/amber) and replace numeric shadow
values with theme.shadows (or computed values derived from theme.spacing/size
tokens) so the glow and shadow follow branding/mode changes; apply the same
tokenization refactor to the other keyframe/box-shadow block referenced in this
file (the second animation near the same component) and ensure imports/access to
the theme (styled-system/theme-ui/ThemeContext) are used where pulseGlow is
defined.

In `@features/admin.onboarding.v1/components/steps/welcome-step.tsx`:
- Around line 113-120: The JSX in welcome-step.tsx hardcodes user-facing strings
for the subtitle and title (the subtitle prop and title prop conditionals using
isReturningUser and greeting); extract these literal strings into i18n keys and
replace the hardcoded text with translations via `@wso2is/i18n` (use
namespace:path.to.key format), adding keys for both returning and new-user
variants and interpolations for greeting, then call t('namespace:key', {
greeting }) (or equivalent) where subtitle and title are set so all text goes
through the i18n system.

In `@features/admin.onboarding.v1/hooks/use-onboarding-fab-visibility.ts`:
- Around line 52-54: The call to useRequiredScopes is currently masking possible
undefined with an unsafe cast ("onboardingFeatureConfig?.scopes?.create as
string[]"); change it to pass a safe default array so the hook receives a
string[] at compile time (e.g.,
useRequiredScopes(onboardingFeatureConfig?.scopes?.create ?? [])); update the
expression that sets hasRequiredCreateScopes to use this default instead of the
as-cast so TypeScript knows the value cannot be undefined while preserving
runtime behavior of useRequiredScopes.

---

Outside diff comments:
In `@features/admin.onboarding.v1/components/onboarding-wizard.tsx`:
- Around line 403-408: The awaited calls to onComplete and onSkip in handleNext
(the async callback defined as handleNext) can reject and currently lack error
handling; wrap each await (the onComplete(onboardingData) branch and the
onSkip() branch) in try/catch blocks and in the catch dispatch an error alert
using dispatch(addAlert({ description: err?.message || String(err), level:
AlertLevels.ERROR, message: 'Onboarding error' })); ensure dispatch and
AlertLevels are imported/available in this component and do not swallow errors
silently (return/exit the handler after dispatching the alert as appropriate).

---

Nitpick comments:
In `@features/admin.onboarding.v1/pages/onboarding-page.tsx`:
- Line 89: Replace the raw boolean checks against
featureConfig?.onboarding?.enabled with the central helper from
`@wso2is/access-control`: import isFeatureEnabled and call it to evaluate
onboarding enablement (e.g., const onboardingEnabled =
isFeatureEnabled(featureConfig, "onboarding")), update all usages that currently
read featureConfig?.onboarding?.enabled (and avoid shadowing the imported name
by renaming the local variable from isFeatureEnabled to onboardingEnabled), and
use onboardingEnabled wherever the file currently performs the raw checks.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 076492f and 04b6b51.

📒 Files selected for processing (15)
  • apps/console/src/public/deployment.config.json
  • features/admin.applications.v1/package.json
  • features/admin.applications.v1/pages/applications.tsx
  • features/admin.home.v1/package.json
  • features/admin.home.v1/pages/home-page.tsx
  • features/admin.onboarding.v1/api/get-onboarding-claim.ts
  • features/admin.onboarding.v1/api/update-onboarding-claim.ts
  • features/admin.onboarding.v1/components/onboarding-wizard.tsx
  • features/admin.onboarding.v1/components/shared/onboarding-fab.tsx
  • features/admin.onboarding.v1/components/steps/welcome-step.tsx
  • features/admin.onboarding.v1/constants/component-ids.ts
  • features/admin.onboarding.v1/hooks/use-onboarding-fab-visibility.ts
  • features/admin.onboarding.v1/hooks/use-onboarding-status.ts
  • features/admin.onboarding.v1/pages/onboarding-page.tsx
  • features/admin.onboarding.v1/public-api.ts

Copy link
Contributor

@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

🧹 Nitpick comments (2)
features/admin.onboarding.v1/hooks/use-onboarding-status.ts (2)

53-64: Type useSelector calls explicitly instead of relying on inferred selector return types.

Current selectors depend on inferred callback returns; the repo rules require explicit hook typing as well.

Example typed selectors
-const uuid: string = useSelector((state: AppState) => state.profile.profileInfo.id);
+const uuid: string = useSelector<AppState, string>(
+    (state: AppState): string => state.profile.profileInfo.id
+);

-const profileInfo: ProfileInfoInterface = useSelector(
-    (state: AppState) => state.profile.profileInfo
-);
+const profileInfo: ProfileInfoInterface = useSelector<AppState, ProfileInfoInterface>(
+    (state: AppState): ProfileInfoInterface => state.profile.profileInfo
+);
As per coding guidelines: "Hooks must use explicit generics on `useState`, `useRef`, and explicit types on `useSelector`."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@features/admin.onboarding.v1/hooks/use-onboarding-status.ts` around lines 53
- 64, Selectors in this file rely on inferred return types from useSelector;
update each useSelector call (for uuid, username, profileInfo, organizationType,
featureConfig) to pass explicit generic type arguments to useSelector (e.g.,
useSelector<AppState, string> or the appropriate interface type) so the hook
return types are explicit; identify the calls by the variable names uuid,
username, profileInfo, userAccountType (derived from profileInfo),
organizationType, and featureConfig and replace their current useSelector
invocations with explicitly typed generics matching AppState and the expected
return type.

33-37: Rename hook return interface to follow repository naming rules.

UseOnboardingStatusReturn should use the Interface suffix.

Proposed rename
-interface UseOnboardingStatusReturn {
+interface UseOnboardingStatusReturnInterface {
     isLoading: boolean;
     markOnboardingComplete: () => Promise<void>;
     shouldShowOnboarding: boolean;
 }
 
-export const useOnboardingStatus = (): UseOnboardingStatusReturn => {
+export const useOnboardingStatus = (): UseOnboardingStatusReturnInterface => {
As per coding guidelines: "Interface names must use the `Interface` suffix."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@features/admin.onboarding.v1/hooks/use-onboarding-status.ts` around lines 33
- 37, The interface name UseOnboardingStatusReturn violates the naming
rule—rename it to UseOnboardingStatusInterface and update all references: change
the declaration interface UseOnboardingStatusReturn { ... } to interface
UseOnboardingStatusInterface { isLoading: boolean; markOnboardingComplete: () =>
Promise<void>; shouldShowOnboarding: boolean; } and update any type annotations,
function return types, exports, and imports that reference
UseOnboardingStatusReturn (e.g., the hook that returns that interface and any
consumers using isLoading, markOnboardingComplete, or shouldShowOnboarding) to
use UseOnboardingStatusInterface instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@features/admin.onboarding.v1/hooks/use-onboarding-status.ts`:
- Around line 112-137: In both evaluateScimClaim and markOnboardingComplete
replace silent failure handling with Redux error alerts: import useDispatch from
react-redux and addAlert and AlertLevels from
`@wso2is/admin.core.v1/hooks/use-snackbar`, create a dispatch via useDispatch(),
and in evaluateScimClaim's catch dispatch addAlert({ description: (include error
message or generic text), level: AlertLevels.ERROR, message: "Failed to evaluate
onboarding claim" }) instead of setShouldShowOnboarding(false); likewise in
markOnboardingComplete's catch dispatch addAlert({ description: (include error
message or generic text), level: AlertLevels.ERROR, message: "Failed to update
onboarding wizard claim" }) instead of console.warn, keeping existing behavior
(e.g., proceed with navigation) after dispatch.

---

Nitpick comments:
In `@features/admin.onboarding.v1/hooks/use-onboarding-status.ts`:
- Around line 53-64: Selectors in this file rely on inferred return types from
useSelector; update each useSelector call (for uuid, username, profileInfo,
organizationType, featureConfig) to pass explicit generic type arguments to
useSelector (e.g., useSelector<AppState, string> or the appropriate interface
type) so the hook return types are explicit; identify the calls by the variable
names uuid, username, profileInfo, userAccountType (derived from profileInfo),
organizationType, and featureConfig and replace their current useSelector
invocations with explicitly typed generics matching AppState and the expected
return type.
- Around line 33-37: The interface name UseOnboardingStatusReturn violates the
naming rule—rename it to UseOnboardingStatusInterface and update all references:
change the declaration interface UseOnboardingStatusReturn { ... } to interface
UseOnboardingStatusInterface { isLoading: boolean; markOnboardingComplete: () =>
Promise<void>; shouldShowOnboarding: boolean; } and update any type annotations,
function return types, exports, and imports that reference
UseOnboardingStatusReturn (e.g., the hook that returns that interface and any
consumers using isLoading, markOnboardingComplete, or shouldShowOnboarding) to
use UseOnboardingStatusInterface instead.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04b6b51 and 9eabf2c.

📒 Files selected for processing (2)
  • features/admin.onboarding.v1/api/get-onboarding-claim.ts
  • features/admin.onboarding.v1/hooks/use-onboarding-status.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • features/admin.onboarding.v1/api/get-onboarding-claim.ts

Copy link
Contributor

@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.

🧹 Nitpick comments (1)
features/admin.applications.v1/pages/applications.tsx (1)

796-796: Consider passing data-componentid for testability.

The OnboardingFab is rendered without props. If the component accepts IdentifiableComponentInterface, consider passing a data-componentid to maintain hierarchical component identification for testing.

♻️ Suggested change
-                <OnboardingFab />
+                <OnboardingFab data-componentid="applications-onboarding-fab" />

Based on learnings: "In the identity-apps repository, prefer using the data-componentid attribute for component identification in tests."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@features/admin.applications.v1/pages/applications.tsx` at line 796,
OnboardingFab is rendered without a data-componentid which reduces testability;
update the JSX where OnboardingFab is instantiated in applications.tsx to pass a
data-componentid prop (e.g. data-componentid="ApplicationsPage.OnboardingFab")
assuming OnboardingFab implements IdentifiableComponentInterface (or add that
prop to its props/type if missing), so tests can reliably target the component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@features/admin.applications.v1/pages/applications.tsx`:
- Line 796: OnboardingFab is rendered without a data-componentid which reduces
testability; update the JSX where OnboardingFab is instantiated in
applications.tsx to pass a data-componentid prop (e.g.
data-componentid="ApplicationsPage.OnboardingFab") assuming OnboardingFab
implements IdentifiableComponentInterface (or add that prop to its props/type if
missing), so tests can reliably target the component.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 06f2828 and adcaed2.

📒 Files selected for processing (1)
  • features/admin.applications.v1/pages/applications.tsx

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.

3 participants