[UI] Restructure Phase 5.b. - Deduplicate Component (Reuse)
#18,661 创建于 2026年4月10日
描述
Prologue
NOTE: THIS IS A CHILD ISSUE FOR THE EPIC AT #18654 See design spec.
Phase 1 breakdown
This checklist breaks down the Modal system workstream in #18661 into contributor-sized requests. All migration tasks depend on #18751.
- #18751
- #18752
- #18753
- #18754
- #18755
- #18756
Guiding Principles
These are load‑bearing. The entire plan enforces these six rules.
- Sistent is the only UI kit. No file outside Sistent's internals may import from @mui/, @material-ui/, or @rjsf/mui. Period.
- Tokens, never literals. No hex, rgb, or named color string may appear in any .tsx/.ts file outside ui/theme/ (a single wrapper module - see §4). Colors come from theme.palette., spacing from theme.spacing(), breakpoints from theme.breakpoints..
- styled() over style={{}}. Inline style props are reserved for dynamic values that cannot be expressed in a styled component (e.g. transform: translate(x,y) for a draggable). Colors are never dynamic enough to justify inline.
- One concept, one home. Every domain (Designs, Workspaces, Connections, …) lives in exactly one folder. Cross‑cutting primitives live under ui/components/shared/.
- Size budget: 400 lines. Any component file > 400 lines is a refactor candidate; > 600 lines is blocked by lint warning; > 1000 lines is a hard error in CI.
- Discoverable filenames. No index.tsx as the only file in a folder. No generic style.tsx, utils.tsx, helpers.tsx, components.tsx - files are named for what they contain.
Implementation
1 Modal system
Today: 22 modal files, each reinventing open/close, header, footer, confirm button styling.
Target: ui/components/shared/Modal/ with exactly these files:
shared/Modal/
├── Modal.tsx # Base: children, onClose, title, size, actions
├── ConfirmModal.tsx # Wraps Modal: title, message, confirm/cancel
├── InfoModal.tsx # Wraps Modal: title, body (Markdown)
├── FormModal.tsx # Wraps Modal: integrates react-hook-form / RJSF
├── useModal.ts # Hook for imperative open/close
└── index.ts
Migration map:
| Current file | New home |
|---|---|
ConfirmationModal.tsx |
ConfirmModal (delete file) |
ExportModal.tsx |
FormModal instance in designs/export/ExportDesignModal.tsx |
ViewInfoModal.tsx |
InfoModal instance in workspaces/ViewInfoModal.tsx |
General/Modals/GenericModal.tsx |
Modal (delete file) |
General/Modals/Modal.tsx |
Delete (consolidates into base Modal) |
General/Modals/InfoModal.tsx |
InfoModal (delete) |
General/Modals/EnvironmentModal.tsx |
environments/EnvironmentFormModal.tsx |
General/Modals/ConnectionModal.tsx |
connections/ConnectionFormModal.tsx |
General/Modals/PublishModal.tsx |
designs/PublishDesignModal.tsx |
General/Modals/ImportModal.tsx |
designs/ImportDesignModal.tsx |
Dashboard/UnsavedChangesModal.tsx |
shared/Modal/UnsavedChangesModal.tsx |
RelationshipBuilder/CreateRelationshipModal.tsx |
registry/CreateRelationshipModal.tsx |
Registry/RegistryModal.tsx |
registry/RegistryModal.tsx |
Settings/Registry/ImportModelModal.tsx |
registry/ImportModelModal.tsx |
Settings/Registry/CreateModelModal.tsx |
registry/CreateModelModal.tsx |
TroubleshootingModalComponent.tsx |
shared/Troubleshooting/TroubleshootingModal.tsx |
SpacesSwitcher/WorkspaceModal.tsx |
workspaces/WorkspaceFormModal.tsx |
SpacesSwitcher/ShareModal.tsx |
workspaces/ShareWorkspaceModal.tsx |
connections/meshSync/RegisterConnectionModal.tsx |
connections/RegisterConnectionModal.tsx |
pages/extension/AccessMesheryModal.tsx |
layout/AccessMesheryModal.tsx |
Every one of these becomes either <Modal>, <ConfirmModal>, <InfoModal>, or <FormModal>. The top‑level GenericModal / Modal.tsx / InfoModal.tsx duplicates disappear.
2 Card system
Create shared/Card/ResourceCard.tsx — a single flippable, menu‑enabled, status‑badge card. Today's MesheryPatternCard, FiltersCard, PerformanceCard, MesheryWorkspaceCard, environment-card, FlipCard all become thin instances passing content slots. Expected LOC savings: ~800.
3 Stepper system
Create shared/Stepper/Stepper.tsx that takes a steps array. Today's DeployStepper, RelationshipFormStepper, CSVStepper, UrlStepper, connections/meshSync/Stepper/* all become data‑driven instances. Expected LOC savings: ~600.
4 EmptyState, LoadingState, PageHeader
EmptyState— replaceLoadingComponents/,EmptyState/K8sContextEmptyState.tsx,connections/meshSync/MeshSyncEmptyState.tsx,Lifecycle/General/empty-state/, and the ad‑hoc empty‑states insideSpacesSwitcher/*Content.tsxfiles.LoadingState— absorbsLoadingComponents/Animations/*(6 animation files). Each animation is a variant.PageHeader— everypages/*currently hand‑rolls a title bar. Replace with<PageHeader title={…} actions={…} breadcrumbs={…} />.
5 Icons
One folder: ui/assets/icons/. Rules:
- Delete
ui/components/icons/(1 file, an index.ts). - Merge
ui/assets/new-icons/*.svg(25 files) intoui/assets/icons/as.tsxcomponents (SVGs become React components for consistency with the existing 76 icons). - Delete
ui/components/shapes/(2 files) →ui/assets/icons/shapes/. - Any
@mui/icons-materialimport is replaced by a Sistent icon or a typed SVG underui/assets/icons/.
6 Hooks consolidation
ui/components/hooks/(3 files) +ui/utils/hooks/→ merged underui/utils/hooks/.ui/themes/hooks.tsx(theme toggler) →ui/theme/useThemePreference.ts.
7 Workspaces consolidation
SpacesSwitcher/ (18 files) and Lifecycle/Workspaces/ (10 files) are two halves of the same feature. Merge into ui/components/workspaces/:
workspaces/
├── switcher/ # was: SpacesSwitcher/SpaceSwitcher, MenuComponent, MobileViewSwitcher
├── list/ # was: Lifecycle/Workspaces/Workspace{Grid,Data}View
├── content/ # was: SpacesSwitcher/*Content.tsx (5 files — should be 1 component + variants)
├── card/ # was: MesheryWorkspaceCard (now instance of shared/Card)
├── modals/ # WorkspaceFormModal, ShareModal
├── hooks/ # was: SpacesSwitcher/hooks.tsx
└── styles/ # was: SpacesSwitcher/styles.tsx + Lifecycle/Workspaces/styles.tsx merged
The 5 *Content.tsx files in SpacesSwitcher/ (MainDesignsContent, MainViewsContent, MyDesignsContent, MyViewsContent, RecentContent, SharedContent, WorkspaceContent) are all the same component with different props — collapse to 1 file with a variant prop.
8 Lifecycle consolidation
Lifecycle/ and DesignLifeCycle/ are unrelated despite the name collision.
Lifecycle/Environments/→components/environments/Lifecycle/Workspaces/→components/workspaces/(merged above)Lifecycle/General/→ absorbed intoshared/DesignLifeCycle/→components/designs/lifecycle/- Delete
Lifecycle/top‑level folder.
Acceptance Tests
- Modal/Card/Stepper count in app code drops to 1 canonical each. max-lines rule promoted to error at 600.
Contributor Guides and Handbook
- 🎨 Wireframes and designs for Meshery UI in Figma (open invite)
- 🖥 Contributing to Meshery UI
- 🙋🏾🙋🏼 Questions: Discussion Forum and Community Slack
- 📺 Self-paced Contributor Trainings