-
Notifications
You must be signed in to change notification settings - Fork 78
Description
Epic: Full React Migration of Lit-Element Dialog Components
Overview
This epic tracks the complete migration of all backend-ai-dialog (Lit-Element + mwc-dialog) usages to React components using BAIModal from the backend.ai-ui package. Unlike the property-mapping approach in #5361, this epic covers full React migration of each parent Lit component that uses backend-ai-dialog.
Background
backend-ai-dialogwraps Material Web Component'smwc-dialog— a library no longer actively maintainedBAIModal(React + Ant Design) is already production-ready with draggable support, theme integration, and z-index management- The
reactToWebComponentbridge pattern is well-established (6 components already migrated: SignupModal, TOTPActivateModal, ResetPasswordRequired, CopyableCodeText, SourceCodeView, SignoutModal) - The
backend.ai-uipackage provides 90+ React components covering all MWC equivalents (BAIButton, BAISelect, BAICard, BAITable, BAIFlex, BAIText, etc.)
Ultimate Goal: Full Lit Dependency Removal
This epic is a critical step toward the ultimate goal of removing all Lit-Element dependencies from the codebase. The dialog migration serves as the primary driver because backend-ai-dialog is the most cross-cutting Lit component.
Current Lit/legacy dependency footprint (28 files in src/components/):
| Dependency | Packages | Files Using |
|---|---|---|
| Lit core | lit, @lit/reactive-element, lit-translate |
28 files |
| Material Web Components | 24 @material/mwc-* packages (v0.27, unmaintained) |
7 files |
| Vaadin | 9 @vaadin/* packages |
1 file (backend-ai-project-switcher.ts) |
Remaining Lit components after this epic (not in scope, tracked separately):
| Component | Lit Dependencies | Notes |
|---|---|---|
backend-ai-webui.ts |
lit, mwc-drawer, mwc-top-app-bar-fixed | App shell — migrate last |
backend-ai-page.ts |
lit | Page routing — migrate with app shell |
backend-ai-edu-applauncher.ts |
lit, mwc-icon-button | Education app launcher variant |
backend-ai-serving-view.ts |
lit | Model serving view |
backend-ai-project-switcher.ts |
lit, @vaadin/combo-box | Project switcher widget |
lablup-notification.ts |
lit, mwc-snackbar | Notification system |
lablup-codemirror.ts |
lit | Code editor wrapper |
lablup-expansion.ts |
lit | Collapsible panel |
lablup-loading-dots.ts |
lit | Loading indicator |
backend-ai-indicator.ts |
lit, mwc-linear-progress | Progress indicator |
backend-ai-indicator-pool.ts |
lit | Indicator management |
backend-ai-tasker.ts |
lit | Background task manager |
backend-ai-metadata-store.ts |
lit | Metadata state store |
backend-ai-settings-store.ts |
lit | Settings state store |
backend-ai-common-utils.ts |
lit | Shared utilities |
backend-ai-painkiller.ts |
lit | Error message handler |
backend-ai-error-view.ts |
lit | Error page view |
backend-ai-general-styles.ts |
lit | Shared CSS styles |
backend-ai-webui-styles.ts |
lit | WebUI-specific styles |
paper-color.ts |
lit | Color definitions |
After Phases 0–4 complete, the 8 dialog-related Lit components will be removed. Phases 5–7 then address the remaining Lit components, ultimately enabling removal of:
lit(v3.3.2)@lit/reactive-element(v2.1.2)lit-translate(v2.0.1)- All 24
@material/mwc-*packages (v0.27.0) - All 9
@vaadin/*packages (v24.9.10) - Rollup-based Lit build pipeline (
rollup.config.ts)
Each sub-issue in this epic should therefore ensure the complete removal of its Lit source file — not just dialog replacement but full component migration to React.
Scope
Components to migrate (8 files, 20+ dialog instances):
| Component | Dialogs | Complexity | Phase |
|---|---|---|---|
backend-ai-splash.ts |
1 (splash-panel) | Low | 1 |
backend-ai-email-verification-view.ts |
2 (success, fail) | Low | 1 |
backend-ai-change-forgot-password-view.ts |
2 (password, fail) | Low | 1 |
lablup-terms-of-service.ts |
1 (TOS dialog) | Medium | 2 |
backend-ai-signup.ts |
3 (signup, block, email-sent) | Medium | 2 |
backend-ai-login.ts |
3 (login, block, help) | High | 3 |
backend-ai-app-launcher.ts |
10 (app, ssh, tensorboard, vnc, xrdp, vscode, tcp, terminal-guide, confirmation, argument) | Extreme | 4 |
backend-ai-edu-applauncher.ts |
0 (delegates to app-launcher) | Moderate | 4 |
backend-ai-app.ts + navigation in backend-ai-webui.ts |
N/A (routing logic) | High | 5 |
Plugin system in backend-ai-webui.ts |
N/A (plugin loading) | High | 5 |
backend-ai-webui.ts (app shell) + 17 remaining Lit utilities |
N/A (root component) | Extreme | 6 |
Implementation Rules
All sub-issues in this epic MUST follow these rules. These rules ensure consistency, quality, and compatibility across all migrated components.
1. React Component Structure
- Add
'use memo'directive at the top of every new component function body for React Compiler optimization. Never remove or rename existing'use memo'directives. - Define a
Propsinterface extendingBAIModalPropswhen wrapping BAIModal:interface MyModalProps extends BAIModalProps { onRequestClose: () => void; // component-specific props }
- All variable names must start with lowercase (camelCase). PascalCase is only for component names, types, and interfaces.
- Use discriminated unions for component variants when a single component handles multiple dialog states.
2. BAI Component Mandatory Usage
Always prefer BAI components over raw Ant Design equivalents. This is a blocking requirement.
| Instead of | Use |
|---|---|
Modal from antd |
BAIModal from backend.ai-ui |
Button from antd |
BAIButton from backend.ai-ui |
Typography.Text from antd |
BAIText from backend.ai-ui |
Flex from antd |
BAIFlex from backend.ai-ui |
Select from antd (when possible) |
BAISelect from backend.ai-ui |
Manual useState for loading |
BAIButton with action prop (handles loading automatically) |
console.log / console.error |
useBAILogger hook |
Ant Design components (Input, Form, Checkbox, Collapse, Carousel, Dropdown, etc.) are acceptable when no BAI equivalent exists.
3. reactToWebComponent Bridge Pattern
Every migrated component must be registered as a web component for backward compatibility with Lit parent components that haven't been migrated yet.
Registration (in react/src/index.tsx):
const MyModal = React.lazy(() => import('./components/MyModal'));
customElements.define(
'backend-ai-react-my-modal',
reactToWebComponent((props) => (
<DefaultProviders {...props}>
<MyModalInWebComponent {...props} />
</DefaultProviders>
)),
);Naming convention: backend-ai-react-{kebab-case-name}
Props communication (Lit → React):
- Pass props as JSON via
valueattribute:value="${JSON.stringify({...})}" - Parse in React via
useWebComponentInfo<T>()hook
Event communication (React → Lit):
- Use
props.dispatchEvent('eventName', detail)to send events to Lit parent - Lit parent listens via
@eventName="${handler}"
Popups and dropdowns: All popups must render inside shadowRoot. This is handled automatically by DefaultProviders — do not override getPopupContainer.
4. State Management
- Dialog open/close: Always use declarative
openprop, never imperativeshow()/hide().// ✅ Correct const [isOpen, setIsOpen] = useState(false); <BAIModal open={isOpen} onCancel={() => setIsOpen(false)} /> // ❌ Wrong — no imperative refs for open/close dialogRef.current.show();
- Form state: Use Ant Design
FormwithForm.useForm(). Do not manage form fields in individualuseStatecalls. - Global state: Use Recoil atoms when state needs to be shared across components. Use React Context for UI-only state scoped to a subtree.
- Fetch/mutation: Use
useTanMutationfor API calls, oruseBAISignedRequestWithPromisefor Backend.AI signed requests. Avoid rawfetch.
5. Modal Lifecycle
- Wrap modals with
BAIUnmountAfterClosewhen they contain forms, to ensure proper state cleanup:<BAIUnmountAfterClose open={isOpen}> <BAIModal open={isOpen} onCancel={...}> <Form form={form}>...</Form> </BAIModal> </BAIUnmountAfterClose>
- Use
destroyOnHidden(ordestroyOnClose) prop on BAIModal when the modal content should be fully unmounted on close. - Use
afterClosecallback for post-close navigation or cleanup.
6. Internationalization (i18n)
- Use
react-i18nextuseTranslationhook:const { t } = useTranslation(); - Reuse existing translation keys from
resources/i18n/when the same text exists in the Lit version. Do not create duplicate keys. - For new strings, follow the key convention:
category.subcategory.KeyName(leaf keys start with Uppercase). - Never hard-code user-facing text. All labels, messages, errors, tooltips must use
t(). - Verify translations exist for all supported languages (en, ko, ja, zh-CN, zh-TW). Add missing translations.
7. Error Handling
- Use
BAIErrorBoundaryfor user-facing error UI,ErrorBoundaryWithNullFallbackfor silent failures. - Use
useBAILoggerhook for all logging. Never useconsole.logdirectly. - No empty catch blocks. Always handle or explicitly return:
// ✅ Good try { await fetchData(); } catch (e) { logger.error('Failed:', e); } // ✅ Good (explicitly ignored) try { await fetchData(); } catch { return undefined; } // ❌ Bad try { await fetchData(); } catch (e) { }
8. Styling and Theming
- Use Ant Design theme tokens via
theme.useToken()for colors, spacing, etc. Never hard-code colors. - Both dark and light themes must work. Test in both modes.
- Use
antd-style(createStyles) only when Ant Design tokens alone are insufficient. - For modal sizing, use the
widthprop on BAIModal andstylesprop for body/header customization.
9. Reference Implementation
react/src/components/SignupModal.tsx is the canonical reference for this migration. Study it before starting any sub-issue:
- How it extends
BAIModalProps - How it uses
Formwith validation rules - How it uses
BAIButtonwithactionprop for async submit - How it uses
BAIFlexfor layout - How it dispatches events back to Lit parent via
dispatchEvent - How it's registered in
react/src/index.tsxwithreactToWebComponent
10. PR and Code Quality
- Each sub-issue should be a separate PR (or stacked PRs via Graphite for closely related work).
- PR title format:
feat(FR-XXXX): descriptionorrefactor(FR-XXXX): description - Run
pnpm run lintandpnpm run formatbefore submitting. - Run
pnpm run relayif any GraphQL fragments are added. - Ensure
pnpm run buildsucceeds with no errors. - Do not leave dead code — when a Lit component is fully replaced, remove it in the same PR or the cleanup PR (chore: Remove backend-ai-dialog and unused MWC dependencies after full migration #5376).
11. Accessibility
- Preserve keyboard navigation (Escape to close, Tab through form fields).
- Ensure
aria-label,role, and focus management work correctly. - BAIModal handles most accessibility automatically via Ant Design — verify it by testing with keyboard only.
12. Electron Compatibility
- Some components behave differently in Electron vs web (especially TCP connections in app-launcher).
- Test both environments if the component has Electron-specific logic.
- Check for
globalThis.isElectronconditionals in the Lit source and preserve equivalent behavior.
13. Complete Lit File Removal
- Each migration must result in the complete removal of the corresponding Lit source file. Do not leave partial Lit components.
- When removing a Lit file, also remove:
- Its type declaration in
src/types/andd/components/ - Its
customElements.define()registration - Any imports of the Lit component from other files (replace with React web component tag or direct React import)
- Its type declaration in
- After removing a Lit file, verify no other Lit component imports or depends on it.
- The ultimate goal is full removal of Lit, MWC, and Vaadin dependencies. Every sub-issue contributes to this goal.
Migration Strategy
Each Lit component will be fully converted to a React component and registered via reactToWebComponent for backward compatibility with Lit parent components. As parent components are also migrated, the web component wrappers can be removed.
Key architectural decisions:
- Declarative state — Replace imperative
show()/hide()with Reactopenstate prop - Ant Design Form — Replace
mwc-textfieldvalidation with Ant Design Form rules - BAI components — Use BAIButton, BAIFlex, BAIModal, BAISelect, etc. instead of MWC equivalents
- Event callbacks — Replace custom events (
dialog-closed,dialog-closing-confirm) with React callback props - i18n — Migrate from
lit-translate(_t,_text) toreact-i18next(t())
Phased Approach
Phase 0: Infrastructure
- feat: Extend BAIModal with missing backend-ai-dialog features for migration #5365 — Extend BAIModal with missing backend-ai-dialog features
Phase 1: Simple Standalone Views
- feat: Migrate backend-ai-splash to React SplashModal #5366 — Migrate backend-ai-splash to React SplashModal
- feat: Migrate backend-ai-email-verification-view to React #5367 — Migrate backend-ai-email-verification-view to React
- feat: Migrate backend-ai-change-forgot-password-view to React #5368 — Migrate backend-ai-change-forgot-password-view to React
Phase 2: Auth-Adjacent Components
- feat: Migrate lablup-terms-of-service to React TermsOfServiceModal #5369 — Migrate lablup-terms-of-service to React TermsOfServiceModal
- feat: Consolidate backend-ai-signup with existing React SignupModal and remove Lit version #5370 — Consolidate backend-ai-signup with existing React SignupModal
Phase 3: Login Flow
- feat: Migrate backend-ai-login to React LoginView #5371 — Migrate backend-ai-login to React LoginView
Phase 4: App Launcher & Edu Launcher
-
feat: Migrate app-launcher SSH/SFTP connection dialog to React #5373— SSH/SFTP dialog (already implemented in React:SFTPConnectionInfoModal.tsx) -
feat: Migrate app-launcher connection info dialogs (VNC, XRDP, TCP, VSCode Desktop) to React #5374— VNC/XRDP/TCP/VSCode dialogs (already implemented in React) -
feat: Migrate app-launcher Tensorboard, Terminal Guide, and Confirmation dialogs to React #5375— Tensorboard/Confirmation dialogs (already implemented in React) - feat: Migrate backend-ai-edu-applauncher to React #5377 — Migrate backend-ai-edu-applauncher to React (last consumer of Lit app-launcher)
- feat: Migrate backend-ai-app-launcher main dialog and infrastructure to React #5372 — Remove Lit
backend-ai-app-launcher.ts(after feat: Migrate backend-ai-edu-applauncher to React #5377 removes last dependency)
Phase 5: Navigation & Plugin System
- refactor: Consolidate navigation from Lit/Redux to React Router #5378 — Consolidate navigation from Lit/Redux to React Router
- refactor: Migrate plugin loading system from Lit to React #5379 — Migrate plugin loading system from Lit to React
Phase 6: App Shell & Full Lit Removal
- refactor: Migrate backend-ai-webui app shell to React and remove Lit core dependencies #5380 — Migrate backend-ai-webui app shell to React and remove all Lit/MWC/Vaadin dependencies
Phase 7: Cleanup & Verification
- chore: Remove backend-ai-dialog and unused MWC dependencies after full migration #5376 — Remove backend-ai-dialog, unused MWC dependencies, and verify full cleanup
Acceptance Criteria
Dialog Migration (Phases 0–4):
- All
backend-ai-dialogusages replaced with React BAIModal-based components - All MWC form components (mwc-textfield, mwc-button, mwc-select, mwc-checkbox) replaced with Ant Design / BAI equivalents
-
backend-ai-dialog.tsdeleted from codebase - No regressions in dialog functionality (open/close, validation, events, styling)
Full Lit Removal (Phases 5–7):
- All Lit-Element components in
src/components/migrated to React or removed - Navigation fully handled by React Router (no Redux page state)
- Plugin loading system migrated to React
-
backend-ai-webui.tsapp shell replaced by React entry point -
lit,@lit/reactive-element,lit-translateremoved frompackage.json - All 24
@material/mwc-*packages removed frompackage.json - All 9
@vaadin/*packages removed frompackage.json - Rollup-based Lit build pipeline removed or replaced
Cross-Cutting:
- i18n translations preserved
- Dark/light theme support maintained
- Keyboard navigation and accessibility maintained
- Bundle size reduced (measured and documented)
Available BAI Components for Migration
The backend.ai-ui package provides all necessary React replacements:
| MWC Component | BAI/Ant Design Replacement |
|---|---|
mwc-dialog |
BAIModal |
mwc-button |
BAIButton (with action prop for async) |
mwc-textfield |
Ant Design Input / Input.Password |
mwc-select |
BAISelect / Ant Design Select |
mwc-checkbox |
Ant Design Checkbox |
mwc-icon-button |
Ant Design Button with icon |
mwc-menu + mwc-list-item |
Ant Design Dropdown / Menu |
lablup-expansion |
Ant Design Collapse |
| CSS flexbox | BAIFlex |
| Text display | BAIText |
Related Issues
- feat: Migrate all backend-ai-dialog usages to existing BAIModal React component #5361 (original property-mapping approach)
- fix: Signup modal visual and interaction bugs after React migration #5360
- migrate the functionality of
backend-ai-edu-applauncher.tsto React. #5159 (older edu-applauncher migration issue — superseded by feat: Migrate backend-ai-edu-applauncher to React #5377)