Files
onyx/web
roshan c6e437b018 refactor(web): migrate replaced refresh-components to Opal (#16242)
## Description

This is the third of four cleanup PRs on top of #16234, which is merged
(stack: #16240 icons, #16241 raw elements, #16242 refresh components,
#16243 Text). It migrates the refresh-components that
`opal/no-replaced-refresh-import` flags, except `Text`, which the next
PR migrates. These are `Card`, `Truncated`, `SelectButton`, `LineItem`
and `Divider`. 13 of 22 files are migrated, and the other 9 are kept for
the reasons below.

### Changes (under `web/src/`)

**`Card` to Opal `Card`** (9 sites in 4 files:
`app/admin/discord-bot/page.tsx`,
`app/admin/discord-bot/[guild-id]/page.tsx`,
`app/app/settings/usage/UsageSettings.tsx`,
`views/admin/GroupsPage/GroupPermissionsSection.tsx`)
- The refresh `Card` put an inner `Section` inside its box, but Opal
`Card` does not. So each site wraps its children in `<Section
alignItems="start" height="fit">` and passes `rounding={4}` for the same
16px corner. One discord-bot card has a single full-width `Section`
child, so it gets no wrapper.
- The variants map like this:
  - `primary` → `border="solid"`;
  - `secondary` → `color="transparent" border="solid"`;
  - the computed `"disabled"` variant → `border="solid" disabled={...}`.

**`Truncated` to `OverflowText`** (9 files:
`app/ee/admin/theme/Preview.tsx`, `lib/app/components.tsx`,
`refresh-components/messages/InfoBlock.tsx`,
`sections/onboarding/components/LLMProviderCard.tsx`,
`ee/sections/SearchCard.tsx`, `layouts/general-layouts.tsx`,
`sections/document-sidebar/ChatDocumentDisplay.tsx`,
`sections/knowledge/agent-knowledge/KnowledgeSearch.tsx`,
`sections/knowledge/SourceHierarchyBrowser.tsx`)
- Each site becomes `as="p" textPosition="text-start"`, with `font` and
`color` set explicitly.
- Sites with no color flag get `color="text-05"`, because the refresh
default is `text-05` and the Opal default is `text-04`.
- `className="line-clamp-2"` becomes `maxLines={2}`.
- `applicationName` can be null, so it renders `{applicationName ??
""}`.

**`SelectButton` to Opal `SelectButton`**
(`sections/knowledge/SourceHierarchyBrowser.tsx`)
- It uses `variant="select-light"`, and `transient` maps to
`interaction={sortDropdownOpen ? "hover" : "rest"}`.

### Visual differences reviewers should check

- **`ChatDocumentDisplay`:** the old tooltip opened with `side="start"`.
`OverflowText` has no side prop, so its tooltip always opens above the
text, aligned to the start.
- **`SourceHierarchyBrowser` sort button:** the label at rest changes
from `text-03` to `text-04`. The size is Opal's default `lg`, where the
old button used `px-2 py-2 rounded-12`.
- **All `OverflowText` sites:**
  - Opal `Text` always adds `px-[2px]`.
- The old `grow w-full` wrapper is gone. The parents are start-aligned,
so the layout should look the same.
- **Card borders:** Opal draws `border-border-01`. The old card used the
global default border color.

### Kept on purpose

- **`app/admin/billing/BillingDetailsView.tsx`, `PlansView.tsx`:** these
Cards pass a `className` (`billing-card-enter`, `billing-payment-card`,
`plan-card`), and Opal `Card` takes no `className`. The deprecation note
on refresh `Card` already says these need a decision.
- **`app/admin/billing/CheckoutView.tsx`:** one Card is clickable and
has `className` and `data-selected`, so it is probably a `SelectCard`.
That needs a design decision.
- **`refresh-components/buttons/LineItem.tsx`:** its title `Truncated`
gets per-variant `line-item-text-*` classes that `OverflowText` cannot
take.
- **`refresh-components/buttons/source-tag/SourceTag.tsx`:** its
`Truncated` shares a `TextStyleProps` object with the refresh `Text`
beside it.
- **`refresh-components/commandmenu/CommandMenu.tsx`:**
- Its `Divider`s use `icon` and highlight states that Opal `Divider`
does not support.
- Its `LineItem` rows depend on muted, action and emphasized colors and
on the keyboard-nav hover in `line-item.css`.
- **`views/admin/UsersPage/EditUserModal.tsx`,
`ServiceAccountsPage/EditServiceAccountModal.tsx`,
`ServiceAccountsPage/ApiKeyFormModal.tsx`:** each has `skeleton`
LineItems (dashed border, 12px text), and neither `LineItemButton` nor
`EmptyMessageCard` matches that look.

## How Has This Been Tested?

- oxlint: in the 13 migrated files, the only
`opal(no-replaced-refresh-import)` diagnostics left are refresh `Text`,
which the next PR migrates. The full run has 0 errors.
- `bun run types:check`: no type errors, and type coverage stays at
99.04%.
- pre-commit (oxfmt, oxlint) passes on the changed files.

## Additional Options

- [ ] [Optional] Please cherry-pick this PR to the latest release
version.



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Hovering over a suppressed tooltip no longer closes its enclosing
tooltip.

* **UI Improvements**
* Text exceeding available space now has consistent overflow handling
across navigation, search results, document lists, onboarding, and
informational messages.
* Admin, usage, permissions, and Discord settings cards now have
consistent borders, rounded corners, disabled states, and content
alignment.
* The knowledge source sort control now reflects its interaction state
while the dropdown is open.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-10-20 00:31:45 +00:00
..
…
…

This is a Next.js project bootstrapped with create-next-app.

Getting Started

Install bun: https://bun.sh/docs/installation Install all dependencies: bun install.

Then, run the development server:

bun run dev

Open http://localhost:3000 with your browser to see the result.

Note: if you are having problems accessing the ^, try setting the WEB_DOMAIN env variable to http://127.0.0.1:3000 and accessing it there.

Tip

Packages are installed automatically when switching branches after package.json changes with pre-commit configured.

Connecting to a Cloud Backend

To test your local frontend development server against a cloud backend (e.g., staging or production), create a .env.local file in the web/ directory with the following configuration:

# Point local dev server to cloud backend
INTERNAL_URL=https://st-dev.onyx.app/api

# Debug auth cookie for authenticating against remote backend
# This cookie is automatically injected into API requests when in development mode
# To get this value:
#   1. Go to https://st-dev.onyx.app (or your target backend URL) and log in
#   2. Open DevTools (F12) → Application → Cookies → [your backend domain]
#   3. Find the "fastapiusersauth" cookie and copy its value
#   4. Paste the value below (without quotes)
# Note: This cookie may expire, so you may need to refresh it periodically
DEBUG_AUTH_COOKIE=your_cookie_value_here

By default, this does NOT override existing cookies, so if you've logged in previously, you may need to delete the cookies for the localhost domain.

Important notes:

  • The .env.local file should be created in the web/ directory (same level as package.json)
  • After creating or modifying .env.local, restart your development server for changes to take effect
  • The DEBUG_AUTH_COOKIE is only used in development mode (NODE_ENV=development)
  • If INTERNAL_URL is not set, the frontend will connect to the local backend at http://127.0.0.1:8080
  • Keep your .env.local file secure and never commit it to version control (it should already be in .gitignore)

Testing

This testing process will reset your application into a clean state. Don't run these tests if you don't want to do this!

Bring up the entire application.

  1. Install playwright dependencies (run bun install first so bunx resolves to the repo-pinned Playwright in node_modules instead of fetching the latest version)
bun install
bunx playwright install
  1. Run playwright (the playwright script expands to playwright test)
bun run playwright

To run a single test:

bun run playwright landing-page.spec.ts

If running locally, interactive options can help you see exactly what is happening in the test.

bun run playwright --ui
bun run playwright --headed
  1. Inspect results

By default, playwright.config.ts is configured to output the results to:

web/output/playwright/
  1. Visual regression screenshots

Screenshots are captured automatically during test runs and saved to web/output/screenshots/. To compare screenshots across CI runs, use:

ods screenshot-diff compare --project admin

For more information, see tools/ods/README.md.