Skip to content

feat(ui): ResetConnectionDialog + ConfigureSSO confirmation restyle#8706

Open
iagodahlem wants to merge 18 commits into
mainfrom
iago/orgs-1588-sdk-improve-confirmation-step-with-new-reset-connection
Open

feat(ui): ResetConnectionDialog + ConfigureSSO confirmation restyle#8706
iagodahlem wants to merge 18 commits into
mainfrom
iago/orgs-1588-sdk-improve-confirmation-step-with-new-reset-connection

Conversation

@iagodahlem
Copy link
Copy Markdown
Member

@iagodahlem iagodahlem commented May 29, 2026

Implements ORGS-1588: a dedicated reset connection dialog and a restyled confirmation step for <ConfigureSSO />.

Summary

  • <ResetConnectionDialog /> — new modal-based, type-to-confirm gated dialog that scopes its backdrop to the wizard's content container via portalRoot. Wraps the destructive flow behind useReverification(user.deleteEnterpriseConnection), clears the local provider selection on success, and asks the wizard to navigate back to the provider selection step.
  • Confirmation step restyle — unified Step.Header with an inline status badge, grouped Enable SSO + Domain rows, two-column configuration details rendered through ProfileSection.ItemList, outlined Configure again, destructive Reset connection, and a sticky info banner inside the step footer when the connection is inactive.
  • Step.Header badge prop — new badge?: ReactNode prop so a step can render an inline status pill next to its title without crowding the existing right-aligned children slot.
  • <OrganizationProfile /> content ref forwarding — propagates the shared ProfileCard content ref into <ConfigureSSO /> so the dialog portals into the wizard chrome (not the document body) when the component is embedded under <OrganizationProfile />.
  • Unit tests for <ResetConnectionDialog /> covering type-to-confirm gating, cancel, and the successful submit chain.

The wizard-wide reset entry (a Step.Footer.Reset compound part on Verify Domain / Configure / Test) ships in a follow-up PR — see ORGS-1550.

Screenshots

Drag-drop the latest captures from the running sandbox here — active + inactive confirmation, plus the reset dialog open.

Confirmation — active Confirmation — inactive Reset dialog
CleanShot 2026-06-01 at 10 05 25@2x CleanShot 2026-06-01 at 10 05 05@2x CleanShot 2026-06-01 at 10 05 48@2x

Test plan

  • Confirmation — inactive: title SSO Successfully configured + Inactive badge inline, grouped Enable SSO + Domain rows, two-column Configuration details with Sign on URL / Issuer / Certificate, outlined Configure again, destructive solid Reset connection, sticky (i) SSO is inactive and you need to enable it to authenticate banner in the footer.
  • Confirmation — active: same layout, Active badge, no inactive banner.
  • Dialog open: clicking Reset opens the dialog centered inside the wizard card; backdrop covers only the card, not the rest of the page; no close X in the corner.
  • Gating: empty input → Reset button disabled; wrong text → still disabled; the exact organization name → enables.
  • Cancel + dismiss: clicking Cancel closes the dialog without side effects.
  • Successful submit: type the org name and click Reset → reverification challenge → user.deleteEnterpriseConnection runs and the enterprise connections query is invalidated.
  • Embedded under <OrganizationProfile />: same behavior; the dialog portals into the wizard chrome, not the page body.
  • Unit tests: pnpm vitest run packages/ui/src/components/ConfigureSSO/__tests__/ResetConnectionDialog.test.tsx green.

Linear: ORGS-1588

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 29, 2026

🦋 Changeset detected

Latest commit: c54190c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@clerk/ui Patch
@clerk/chrome-extension Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel Bot commented May 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jun 1, 2026 1:13pm

Request Review

Comment thread .changeset/sso-confirmation-restyle.md Outdated
Comment thread packages/ui/src/components/ConfigureSSO/__tests__/ResetConnectionDialog.test.tsx Outdated
Comment thread packages/ui/src/components/ConfigureSSO/__tests__/ResetConnectionDialog.test.tsx Outdated
Comment thread packages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsx Outdated
Comment thread packages/ui/src/components/ConfigureSSO/ResetConnectionDialog.tsx Outdated
const { enterpriseConnection, deleteEnterpriseConnection, setProvider } = useConfigureSSO();
const { goToStep } = useWizard();

const deleteConnection = useReverification((id: string) => deleteEnterpriseConnection(id));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need reverification here? I'm not sure if all FAPI mutations rely on it

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Keeping it — useReverification wraps every sensitive user.* mutation in @clerk/ui (delete account, delete passkey, etc.), and the pre-refactor inline ResetConnectionForm used it for the same destructive delete call. Skipping it here would diverge from the rest of the component surface.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Once we refactor those endpoints to the organization scoped instead of the user scope, then I think those won't be needed

iagodahlem added 15 commits June 1, 2026 09:17
Standalone modal dialog with type-to-confirm gating. Wraps the destructive
delete flow (useReverification + deleteEnterpriseConnection + provider clear +
wizard rewind to select-provider). Controlled via isOpen/onClose props with
the confirmation value injected by the caller.

Widens ConfigureSSOContext.setProvider to accept undefined so the dialog can
clear the local provider selection after deleting the connection, and adds
the configureSSO.resetConnectionDialog localization keys (and matching type
entries in @clerk/shared) for the dialog copy.
Replaces the inline reset confirmation card (Action.Root / Action.Card pattern)
with the new ResetConnectionDialog modal. The destructive button now opens the
dialog instead of expanding an inline form; the dialog handles type-to-confirm,
reverification, deletion, and wizard rewind internally.
…tainer

Portals the dialog into the wizard's content container instead of the document
body and switches the backdrop to absolute positioning so it stays inside the
ConfigureSSO card. Disables the modal-context toggle so the auto-rendered
close button is suppressed — the Cancel button is the explicit dismiss for the
destructive flow.
Backdrop now uses a transparent fill plus backdrop-filter blur so the wizard
chrome shows through without an opaque tint. Card switches to a tighter border
radius, start-aligned text, and reduced padding to match the design spec for
the inline reset confirmation.
The OrganizationProfile self-serve SSO page was creating its own contentRef
that diverged from the ProfileCard content ref. ConfigureSSO needs the same
container ref to portal child modals (ResetConnectionDialog) into the wizard
chrome instead of the document body, so the SSO page now receives the shared
ref from the surrounding routes and forwards it down.
Unifies the SSO Successfully configured title with the status badge, lays out
configuration details in a two-column grid, swaps the configure-again and
reset connection actions to dedicated outlined and destructive buttons, and
adds a sticky inactive banner inside the step footer when the connection is
disabled.
Covers the type-to-confirm gating, cancel and reset interactions, and the
successful submit chain (delete + provider clear + wizard rewind + onClose).
Lets a step render an inline badge next to the title without crowding the
right-aligned children slot. The SSO confirmation step now passes its active
status badge through this prop instead of layering its own header component
inside the body.
The hand-rolled grid layered onto the confirmation step recreated what
ProfileSection.Root already provides for every other profile section. Each
detail row now lives inside its own ProfileSection.Root, restoring the
profile-section descriptors and consistent responsive collapse while keeping
the outlined Configure again button, destructive Reset connection button,
status header badge, and inactive footer banner from the recent restyle.
Drops the top border and redundant top padding from the Domain section so it
visually pairs with the Enable SSO row above it. Matches the design intent of
keeping the connection-state controls (toggle + domain) in a single block,
separated from Configuration details and Reset connection by the existing
section dividers.
Wraps the confirmation body in Step.Section so it picks up the canonical
section padding instead of hand-rolling padding on Step.Body. Drops the top
border and redundant top padding from the Enable SSO section so it visually
joins the header above. Aligns the Configuration details section title to the
top via centered={false} and folds the Configure again action into the same
grid as the detail rows so it shares their column alignment.
…ion details

Drops the hand-rolled grid that paired each detail label with its value and
rebuilds the rows on top of ProfileSection.ItemList + ProfileSection.Item.
The Configure again action moves below the row list and reuses the section's
inset padding so it lines up with the row labels above.
Flips the detail rows from space-between to start justification and gives the
label a fixed-width column matching the previous grid minimum so labels stop
wrapping when values are long and all three values line up at the same x.
Values keep truncating with ellipsis when they overflow.
Widens the Sign on URL label to fit the longest copy without wrapping and
sets an explicit gap on the item list so the detail rows space consistently
without inheriting the default tight gap from ProfileSection.ItemList.
Folds the per-commit changeset stubs accumulated during this PR into a single
generated changeset that describes the whole change end to end.
@iagodahlem iagodahlem force-pushed the iago/orgs-1588-sdk-improve-confirmation-step-with-new-reset-connection branch from 929090b to b190354 Compare June 1, 2026 12:17
Wraps the configuration item list and the Configure again action in a Col
with a shared gap, lets the items inherit the default space-between layout
with a fixed-width label column, and aligns the Issuer label width to the
Sign on URL row so labels sit on a consistent column.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 1, 2026

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@8706

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@8706

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@8706

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@8706

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@8706

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@8706

@clerk/express

npm i https://pkg.pr.new/@clerk/express@8706

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@8706

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8706

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@8706

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@8706

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@8706

@clerk/react

npm i https://pkg.pr.new/@clerk/react@8706

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@8706

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@8706

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@8706

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@8706

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8706

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@8706

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@8706

commit: c54190c

Updates the dialog test name to read as a behavioral assertion and removes
the verbose confirmation value comment now that the prop name carries the
intent on its own.
@iagodahlem iagodahlem marked this pull request as ready for review June 1, 2026 12:56
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

API Changes Report

Generated by snapi on 2026-06-01T13:15:28.891Z

Summary

Metric Count
Packages analyzed 6
Packages with changes 1
🔴 Breaking changes 1
🟡 Non-breaking changes 0
🟢 Additions 0

Warning
1 breaking change(s) detected - Major version bump required


@clerk/shared

Current version: 4.14.0
Recommended bump: MAJOR → 5.0.0

Subpath ./types

🔴 Breaking Changes (1)

Changed: __internal_LocalizationResource
Diff (before: 1680 lines, after: 1691 lines). Click to expand.
// ... 1208 unchanged lines elided ...
      navbar: {
        title: LocalizationValue;
      };
+     resetConnectionDialog: {
+       cancelButton: LocalizationValue;
+       confirmationFieldLabel: LocalizationValue<'name'>;
+       confirmationFieldPlaceholder: LocalizationValue<'name'>;
+       resetButton: LocalizationValue;
+       subtitle: LocalizationValue;
+       title: LocalizationValue;
+     };
      selectProviderStep: {
        title: LocalizationValue;
        subtitle: LocalizationValue;
        saml: {
          groupLabel: LocalizationValue;
          okta: LocalizationValue;
          customSaml: LocalizationValue;
        };
        warning: LocalizationValue;
      };
      verifyEmailDomainStep: {
        title: LocalizationValue;
        subtitle: LocalizationValue;
        addEmailAddress: {
          formTitle: LocalizationValue;
          formSubtitle: LocalizationValue;
          inputPlaceholder: LocalizationValue;
          inputLabel: LocalizationValue;
        };
        emailCode: {
          formTitle: LocalizationValue;
          formSubtitle: LocalizationValue<'identifier'>;
          resendButton: LocalizationValue;
          verified: {
            title: LocalizationValue;
            subtitle: LocalizationValue;
            inputLabel: LocalizationValue;
          };
        };
        domainTaken: {
          title: LocalizationValue<'domain'>;
          subtitle: LocalizationValue;
        };
      };
      testConfigurationStep: {
        title: LocalizationValue;
        subtitle: LocalizationValue;
        error__noSuccessfulTestRun: LocalizationValue;
        testUrl: {
          actionLabel__open: LocalizationValue;
        };
        testResults: {
          title: LocalizationValue;
          actionLabel__refresh: LocalizationValue;
          polling: LocalizationValue;
          status__success: LocalizationValue;
          status__failed: LocalizationValue;
          status__pending: LocalizationValue;
          empty: {
            title: LocalizationValue;
            subtitle: LocalizationValue;
          };
        };
        testRunDetails: {
          title: LocalizationValue;
          runDetails: {
            sectionTitle: LocalizationValue;
            timestamp: LocalizationValue;
            status: LocalizationValue;
            errorCode: LocalizationValue;
            fullMessage: LocalizationValue;
            actionLabel__copy: LocalizationValue;
            actionLabel__copied: LocalizationValue;
          };
          parsedUserInfo: {
            sectionTitle: LocalizationValue;
            email: LocalizationValue;
            firstName: LocalizationValue;
          };
          howToFix: {
            sectionTitle: LocalizationValue;
            actionLabel__viewDocumentation: LocalizationValue;
            saml_user_attribute_missing: {
              intro: LocalizationValue;
              step1: LocalizationValue;
              step2: LocalizationValue;
              step3: LocalizationValue;
            };
            saml_response_relaystate_missing: {
              description: LocalizationValue;
            };
            saml_email_address_domain_mismatch: {
              description: LocalizationValue;
            };
            oauth_access_denied: {
              description: LocalizationValue;
            };
            oauth_token_exchange_error: {
              description: LocalizationValue;
            };
            oauth_fetch_user_error: {
              intro: LocalizationValue;
              step1: LocalizationValue;
              step2: LocalizationValue;
            };
          };
        };
      };
      configureStep: {
        attributeMappingTable: {
          badges: {
            required: LocalizationValue;
            optional: LocalizationValue;
          };
        };
        samlOkta: {
          mainHeaderTitle: LocalizationValue;
          createAppStep: {
            headerSubtitle: LocalizationValue;
            createAppInstructions: {
              title: LocalizationValue;
              step1: LocalizationValue;
              step2: LocalizationValue;
              step3: LocalizationValue;
              step4: LocalizationValue;
              step5: LocalizationValue;
            };
            serviceProviderInstructions: {
              title: LocalizationValue;
              paragraph1: LocalizationValue;
              paragraph2: LocalizationValue;
              serviceProviderFields: {
                acsUrl: {
                  label: LocalizationValue;
                };
                spEntityId: {
                  label: LocalizationValue;
                };
              };
            };
            completeSamlIntegrationInstructions: {
              title: LocalizationValue;
              step1: LocalizationValue;
              step2: LocalizationValue;
            };
          };
          attributeMappingStep: {
            headerSubtitle: LocalizationValue;
            paragraph: LocalizationValue;
            step1: LocalizationValue;
            step2: LocalizationValue;
            attributeMappingTable: {
              columns: {
                name: LocalizationValue;
                expression: LocalizationValue;
              };
              rows: {
                email: {
                  name: LocalizationValue;
                  expression: LocalizationValue;
                };
                firstName: {
                  name: LocalizationValue;
                  expression: LocalizationValue;
                };
                lastName: {
                  name: LocalizationValue;
                  expression: LocalizationValue;
                };
              };
            };
          };
          assignUsersStep: {
            headerSubtitle: LocalizationValue;
            assignUsersInstructions: {
              title: LocalizationValue;
              paragraph: LocalizationValue;
              step1: LocalizationValue;
              step2: LocalizationValue;
              step3: LocalizationValue;
              step4: LocalizationValue;
              step5: LocalizationValue;
            };
          };
          identityProviderMetadataStep: {
            headerSubtitle: LocalizationValue;
            modes: {
              title: LocalizationValue;
              ariaLabel: LocalizationValue;
              metadataUrl: LocalizationValue;
              manual: LocalizationValue;
            };
            metadataUrl: {
              label: LocalizationValue;
              placeholder: LocalizationValue;
              description: LocalizationValue;
            };
            manual: {
              description: LocalizationValue;
              signOnUrl: {
                label: LocalizationValue;
                placeholder: LocalizationValue;
              };
              issuer: {
                label: LocalizationValue;
                placeholder: LocalizationValue;
              };
              signingCertificate: {
                label: LocalizationValue;
                uploadFile: LocalizationValue;
                replaceFile: LocalizationValue;
                removeFile: LocalizationValue;
                fileUploaded: LocalizationValue;
              };
            };
          };
        };
        samlCustom: {
          mainHeaderTitle: LocalizationValue;
          createAppStep: {
            headerSubtitle: LocalizationValue;
            createAppInstructions: {
              title: LocalizationValue;
              paragraph: LocalizationValue;
            };
            serviceProviderFields: {
              acsUrl: {
                label: LocalizationValue;
              };
              spEntityId: {
                label: LocalizationValue;
              };
            };
          };
          attributeMappingStep: {
            headerSubtitle: LocalizationValue;
            paragraph: LocalizationValue;
            attributeMappingTable: {
              title: LocalizationValue;
              columns: {
                userProfile: LocalizationValue;
                attributeName: LocalizationValue;
              };
              rows: {
                email: {
                  userProfile: LocalizationValue;
                  attributeName: LocalizationValue;
                };
                firstName: {
                  userProfile: LocalizationValue;
                  attributeName: LocalizationValue;
                };
                lastName: {
                  userProfile: LocalizationValue;
                  attributeName: LocalizationValue;
                };
              };
            };
          };
          assignUsersStep: {
            headerSubtitle: LocalizationValue;
            title: LocalizationValue;
            paragraph: LocalizationValue;
          };
          identityProviderMetadataStep: {
            headerSubtitle: LocalizationValue;
            modes: {
              title: LocalizationValue;
              ariaLabel: LocalizationValue;
              metadataUrl: LocalizationValue;
              manual: LocalizationValue;
            };
            metadataUrl: {
              label: LocalizationValue;
              placeholder: LocalizationValue;
              description: LocalizationValue;
            };
            manual: {
              description: LocalizationValue;
              signOnUrl: {
                label: LocalizationValue;
                placeholder: LocalizationValue;
              };
              issuer: {
                label: LocalizationValue;
                placeholder: LocalizationValue;
              };
              signingCertificate: {
                label: LocalizationValue;
                uploadFile: LocalizationValue;
                replaceFile: LocalizationValue;
                removeFile: LocalizationValue;
                fileUploaded: LocalizationValue;
              };
            };
          };
        };
      };
      confirmation: {
        statusSection: {
          title: LocalizationValue;
          activeBadge: LocalizationValue;
          inactiveBadge: LocalizationValue;
        };
        enableSection: {
          title: LocalizationValue;
        };
        domainSection: {
          title: LocalizationValue;
        };
        configurationSection: {
          title: LocalizationValue;
          ssoUrlLabel: LocalizationValue;
          issuerLabel: LocalizationValue;
          certificateLabel: LocalizationValue;
          configureAgainLink: LocalizationValue;
        };
        resetSection: {
          title: LocalizationValue;
          warning: LocalizationValue;
          confirmationFieldLabel: LocalizationValue<'name'>;
          submitButton: LocalizationValue;
+       };
+       inactiveBanner: {
+         title: LocalizationValue;
        };
      };
    };
// ... 154 unchanged lines elided ...

Breaking change in type alias __internal_LocalizationResource: Type changed: {locale:string;maintenanceMode:LocalizationValue;roles:{[r:string]:LocalizationValue;};socialButtonsBlockButton:Localiz…{locale:string;maintenanceMode:LocalizationValue;roles:{[r:string]:LocalizationValue;};socialButtonsBlockButton:Localiz…


Report generated by snapi

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: df326126-532b-42cc-a95c-067c13297d66

📥 Commits

Reviewing files that changed from the base of the PR and between 354109b and c54190c.

📒 Files selected for processing (2)
  • packages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsx
  • packages/ui/src/components/ConfigureSSO/__tests__/ResetConnectionDialog.test.tsx
💤 Files with no reviewable changes (2)
  • packages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsx
  • packages/ui/src/components/ConfigureSSO/tests/ResetConnectionDialog.test.tsx

📝 Walkthrough

Walkthrough

This PR refactors the SSO wizard confirmation step from an inline reset confirmation card to a dedicated modal dialog. It adds localization strings and type definitions for the reset dialog and inactive banner status, updates Step.Header to display an optional status badge, introduces a new ResetConnectionDialog component with form validation and async deletion flow, restructures the confirmation step layout with reorganized sections and updated styling, and threads content ref through the OrganizationProfile hierarchy to enable proper dialog portaling within the wizard chrome.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • clerk/javascript#8531: Refactors the same ConfirmationStep component's reset confirmation UX, which this PR builds upon with a modal-based approach.
  • clerk/javascript#8544: Adds contentRef support in ConfigureSSO/context; related to this PR's contentRef forwarding to enable correct dialog portaling.
  • clerk/javascript#8600: Adds the self-serve SSO route and page integration in OrganizationProfile that this PR extends with contentRef forwarding for proper dialog portaling.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main changes: adding a ResetConnectionDialog component and restyling the ConfigureSSO confirmation step, which aligns with the core objectives of the PR.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, providing detailed context about the new ResetConnectionDialog, confirmation step restyle, Step.Header badge prop, OrganizationProfile ref forwarding, and unit tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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


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

Copy link
Copy Markdown
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 (1)
packages/ui/src/components/ConfigureSSO/steps/ConfirmationStep.tsx (1)

252-279: 💤 Low value

Consider disabling reset button when organization name is unavailable.

If organization?.name is falsy, confirmationValue becomes an empty string, making the dialog's submit button permanently disabled since canSubmit = Boolean(confirmationValue && ...) will be false. Users could open the dialog but would be unable to submit, only cancel.

Consider disabling the reset button or hiding the section when organization name is unavailable:

💡 Suggested improvement
 const ResetConnectionSection = (): JSX.Element => {
   const { organization } = useOrganization();
   const [isOpen, setIsOpen] = useState(false);
+  const confirmationValue = organization?.name ?? '';

   return (
     <ProfileSection.Root
       title={localizationKeys('configureSSO.confirmation.resetSection.title')}
       id='resetSso'
     >
       <Flex justify='start'>
         <Button
           elementDescriptor={descriptors.configureSSOConfirmationResetButton}
           variant='solid'
           colorScheme='danger'
           size='sm'
+          isDisabled={!confirmationValue}
           onClick={() => setIsOpen(true)}
           localizationKey={localizationKeys('configureSSO.confirmation.resetSection.title')}
         />
       </Flex>

       <ResetConnectionDialog
         isOpen={isOpen}
         onClose={() => setIsOpen(false)}
-        confirmationValue={organization?.name ?? ''}
+        confirmationValue={confirmationValue}
       />
     </ProfileSection.Root>
   );
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/components/ConfigureSSO/steps/ConfirmationStep.tsx` around
lines 252 - 279, The ResetConnectionSection opens ResetConnectionDialog with
confirmationValue set to organization?.name which can be empty and thus prevents
submission; update ResetConnectionSection to disable (or hide) the reset Button
when organization?.name is falsy so users cannot open an un-submittable dialog.
Specifically, check organization?.name before rendering or pass a disabled prop
to the Button rendered in ResetConnectionSection (the Button that calls
setIsOpen(true)) and ensure the UI conveys why it’s disabled; alternatively skip
rendering the entire ProfileSection.Root when organization?.name is missing to
avoid launching ResetConnectionDialog with an empty confirmationValue.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/components/ConfigureSSO/ResetConnectionDialog.tsx`:
- Around line 57-64: The placeholder for the form control is using the raw
confirmationValue instead of the localization key; update the useFormControl
call for confirmationField to pass
localizationKeys('configureSSO.resetConnectionDialog.confirmationFieldPlaceholder',
{ name: confirmationValue }) as the placeholder so translators can control
formatting. Locate the confirmationField definition
(useFormControl('deleteConfirmation', ...)) and replace the current placeholder
argument with the localized key while keeping the label using
configureSSO.resetConnectionDialog.confirmationFieldLabel unchanged.

---

Nitpick comments:
In `@packages/ui/src/components/ConfigureSSO/steps/ConfirmationStep.tsx`:
- Around line 252-279: The ResetConnectionSection opens ResetConnectionDialog
with confirmationValue set to organization?.name which can be empty and thus
prevents submission; update ResetConnectionSection to disable (or hide) the
reset Button when organization?.name is falsy so users cannot open an
un-submittable dialog. Specifically, check organization?.name before rendering
or pass a disabled prop to the Button rendered in ResetConnectionSection (the
Button that calls setIsOpen(true)) and ensure the UI conveys why it’s disabled;
alternatively skip rendering the entire ProfileSection.Root when
organization?.name is missing to avoid launching ResetConnectionDialog with an
empty confirmationValue.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: ae810c5c-535a-41cc-8ed2-11c203be67c1

📥 Commits

Reviewing files that changed from the base of the PR and between 35020c3 and 354109b.

📒 Files selected for processing (11)
  • .changeset/cool-boats-burn.md
  • packages/localizations/src/en-US.ts
  • packages/shared/src/types/localization.ts
  • packages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsx
  • packages/ui/src/components/ConfigureSSO/ResetConnectionDialog.tsx
  • packages/ui/src/components/ConfigureSSO/__tests__/ResetConnectionDialog.test.tsx
  • packages/ui/src/components/ConfigureSSO/elements/Step.tsx
  • packages/ui/src/components/ConfigureSSO/steps/ConfirmationStep.tsx
  • packages/ui/src/components/OrganizationProfile/OrganizationProfileRoutes.tsx
  • packages/ui/src/components/OrganizationProfile/OrganizationSelfServeSSOPage.tsx
  • packages/ui/src/components/OrganizationProfile/index.tsx

Comment on lines +57 to +64
const confirmationField = useFormControl('deleteConfirmation', '', {
type: 'text',
label: localizationKeys('configureSSO.resetConnectionDialog.confirmationFieldLabel', {
name: confirmationValue,
}),
isRequired: true,
placeholder: confirmationValue,
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the localized placeholder key instead of raw organization text.

Line 63 bypasses configureSSO.resetConnectionDialog.confirmationFieldPlaceholder, so translators cannot control placeholder formatting and the new key is effectively unused.

Proposed fix
   const confirmationField = useFormControl('deleteConfirmation', '', {
     type: 'text',
     label: localizationKeys('configureSSO.resetConnectionDialog.confirmationFieldLabel', {
       name: confirmationValue,
     }),
     isRequired: true,
-    placeholder: confirmationValue,
+    placeholder: localizationKeys('configureSSO.resetConnectionDialog.confirmationFieldPlaceholder', {
+      name: confirmationValue,
+    }),
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const confirmationField = useFormControl('deleteConfirmation', '', {
type: 'text',
label: localizationKeys('configureSSO.resetConnectionDialog.confirmationFieldLabel', {
name: confirmationValue,
}),
isRequired: true,
placeholder: confirmationValue,
});
const confirmationField = useFormControl('deleteConfirmation', '', {
type: 'text',
label: localizationKeys('configureSSO.resetConnectionDialog.confirmationFieldLabel', {
name: confirmationValue,
}),
isRequired: true,
placeholder: localizationKeys('configureSSO.resetConnectionDialog.confirmationFieldPlaceholder', {
name: confirmationValue,
}),
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/components/ConfigureSSO/ResetConnectionDialog.tsx` around
lines 57 - 64, The placeholder for the form control is using the raw
confirmationValue instead of the localization key; update the useFormControl
call for confirmationField to pass
localizationKeys('configureSSO.resetConnectionDialog.confirmationFieldPlaceholder',
{ name: confirmationValue }) as the placeholder so translators can control
formatting. Locate the confirmationField definition
(useFormControl('deleteConfirmation', ...)) and replace the current placeholder
argument with the localized key while keeping the label using
configureSSO.resetConnectionDialog.confirmationFieldLabel unchanged.

The Reset connection button only appears on the confirmation step, which
itself only renders when the enterprise connection exists, so the missing
connection branch is not reachable in practice. Removes the matching test
and the stale provider setter JSDoc that no longer describes the flow.
Comment on lines +84 to +109
<Card.Root sx={t => ({ borderRadius: t.radii.$md })}>
<Card.Content sx={t => ({ textAlign: 'start', padding: t.sizes.$5 })}>
<FormContainer
headerTitle={localizationKeys('configureSSO.resetConnectionDialog.title')}
headerSubtitle={localizationKeys('configureSSO.resetConnectionDialog.subtitle')}
sx={t => ({ gap: t.space.$4 })}
>
<Form.Root onSubmit={onSubmit}>
<Col gap={4}>
<Form.ControlRow elementId={confirmationField.id}>
<Form.PlainInput
{...confirmationField.props}
ignorePasswordManager
/>
</Form.ControlRow>
<FormButtonContainer>
<Form.SubmitButton
block={false}
colorScheme='danger'
isDisabled={!canSubmit}
localizationKey={localizationKeys('configureSSO.resetConnectionDialog.resetButton')}
/>
<Form.ResetButton
block={false}
localizationKey={localizationKeys('configureSSO.resetConnectionDialog.cancelButton')}
onClick={onClose}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we add descriptors to this modal?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants