Component Library Guide
This guide covers the comprehensive set of reusable UI components and specialized patterns used throughout Waldur HomePort.
The application features a comprehensive set of reusable UI components organized by category:
Tables and Data Display
| Component | 
Location | 
Description | 
Key Features | 
| Table | 
src/table/Table.tsx | 
Main table component | 
Filtering, sorting, pagination, column visibility, export | 
| ActionButton | 
src/table/ActionButton.tsx | 
Reusable action button | 
Tooltip, loading state, multiple variants | 
| ActionsDropdown | 
src/table/ActionsDropdown.tsx | 
Dropdown for table actions | 
Bulk operations, contextual actions | 
| ExpandableContainer | 
src/table/ExpandableContainer.tsx | 
Collapsible row details | 
Table row expansion, detail views | 
| TablePagination | 
src/table/TablePagination.tsx | 
Pagination controls | 
Page navigation, size selection | 
| Component | 
Location | 
Description | 
Key Features | 
| WizardForm | 
src/form/WizardForm.tsx | 
Multi-step form wizard | 
Step navigation, validation, progress indicator | 
| VStepperFormStepCard | 
src/form/VStepperFormStep.tsx | 
Card-based form step | 
Loading state, disabled state with tooltip | 
| AwesomeCheckbox | 
src/core/AwesomeCheckbox.tsx | 
Enhanced checkbox | 
Switch-style, tooltip support | 
| SelectField | 
src/form/SelectField.tsx | 
Dropdown selection | 
Options, search, validation | 
| StringField | 
src/form/StringField.tsx | 
Text input field | 
Validation, placeholder, help text | 
| NumberField | 
src/form/NumberField.tsx | 
Numeric input | 
Min/max validation, step control | 
| DateField | 
src/form/DateField.tsx | 
Date picker | 
Date selection, validation | 
| FileUploadField | 
src/form/FileUploadField.tsx | 
File upload | 
Drag & drop, validation | 
| MarkdownEditor | 
src/form/MarkdownEditor.tsx | 
Markdown editor | 
Preview, syntax highlighting | 
| SecretField | 
src/form/SecretField.tsx | 
Password/secret input | 
Show/hide toggle, validation | 
| SubmitButton | 
src/form/SubmitButton.tsx | 
Submit button | 
Loading state, disabled state | 
Modal and Dialog Components
| Component | 
Location | 
Description | 
Key Features | 
| ModalDialog | 
src/modal/ModalDialog.tsx | 
Base modal component | 
Header, body, footer, icon support | 
| ConfirmationDialog | 
src/modal/ConfirmationDialog.tsx | 
Confirmation modal | 
Destructive actions, custom text | 
| ActionDialog | 
src/modal/ActionDialog.tsx | 
Generic action dialog | 
Form support, validation | 
Navigation Components
| Component | 
Location | 
Description | 
Key Features | 
| TabsList | 
src/navigation/TabsList.tsx | 
Tab navigation | 
Nested dropdowns, active detection | 
| Layout | 
src/navigation/Layout.tsx | 
Application layout | 
Responsive, sidebar, header | 
| Breadcrumbs | 
src/navigation/header/breadcrumb/Breadcrumbs.tsx | 
Navigation breadcrumbs | 
Hierarchical navigation | 
Cards and Layout Components
| Component | 
Location | 
Description | 
Key Features | 
| Panel | 
src/core/Panel.tsx | 
Basic card panel | 
Header, actions, flexible content | 
| AccordionCard | 
src/core/AccordionCard.tsx | 
Collapsible card | 
Toggle functionality, custom styling | 
| WidgetCard | 
src/dashboard/WidgetCard.tsx | 
Dashboard widget | 
Flexible layout, action dropdown | 
| StatisticsCard | 
src/core/StatisticsCard.tsx | 
Statistics display | 
Large value display, "View all" link | 
Data Display Components
| Component | 
Location | 
Description | 
Key Features | 
| Badge | 
src/core/Badge.tsx | 
Status indicator | 
Multiple variants, icon support, tooltip | 
| StateIndicator | 
src/core/StateIndicator.tsx | 
Status with animation | 
Loading animation, color variants | 
| BooleanBadge | 
src/core/BooleanBadge.tsx | 
Boolean indicator | 
Yes/No display, true/false states | 
| TruncatedText | 
src/core/TruncatedText.tsx | 
Responsive text | 
Automatic truncation, expandable | 
| TruncatedDescription | 
src/core/TruncatedDescription.tsx | 
Description text | 
Read more/less functionality | 
| ImagePlaceholder | 
src/core/ImagePlaceholder.tsx | 
Image fallback | 
Automatic sizing, circular option | 
| Avatar | 
src/core/Avatar.tsx | 
User avatar | 
Profile pictures, initials fallback | 
Loading and State Components
| Component | 
Location | 
Description | 
Key Features | 
| LoadingSpinner | 
src/core/LoadingSpinner.tsx | 
Loading indicator | 
Consistent styling, size variants | 
| LoadingErred | 
src/core/LoadingErred.tsx | 
Error state display | 
Error handling, retry actions | 
Chart and Visualization
| Component | 
Location | 
Description | 
Key Features | 
| EChart | 
src/core/EChart.tsx | 
Apache ECharts wrapper | 
Theme support, export functionality | 
| EChartActions | 
src/core/EChartActions.tsx | 
Chart actions | 
Export buttons, chart controls | 
Utility Components
| Component | 
Location | 
Description | 
Key Features | 
| CopyToClipboard | 
src/core/CopyToClipboard.tsx | 
Copy functionality | 
Click to copy, success feedback | 
| CopyToClipboardButton | 
src/core/CopyToClipboardButton.tsx | 
Copy button | 
Icon button, tooltip | 
| Tooltip | 
src/core/Tooltip.tsx | 
Tooltip wrapper | 
Help text, positioning | 
| ProgressSteps | 
src/core/ProgressSteps.tsx | 
Step indicator | 
Multi-step processes, progress | 
Component Design Principles
- TypeScript interfaces for comprehensive type safety
 
- Consistent styling using React Bootstrap and custom classes
 
- Accessibility features with proper ARIA attributes
 
- Responsive design with mobile-first approach
 
- Theme support with light/dark mode compatibility
 
- Loading states with integrated spinner functionality
 
- Error handling with proper error boundaries
 
- Internationalization with translate function usage
 
These components provide a comprehensive foundation for building consistent, accessible, and maintainable UI throughout the Waldur HomePort application.
BaseDeployPage Component Pattern
The BaseDeployPage component (located at src/marketplace/deploy/DeployPage.tsx) serves as the central foundation for all marketplace offering deployment/ordering flows. It provides a standardized, multi-step form interface that can be configured for different types of cloud resources and services.
Architecture and Purpose
BaseDeployPage handles:
- Step Management: Progressive form steps with validation and completion tracking
 
- State Management: Integration with Redux for form state and user selections
 
- Form Validation: Real-time validation and error display
 
- Layout Management: Sidebar layout with progress tracking
 
- API Integration: Order submission and error handling
 
- Context-Aware Initialization: Auto-populates organization/project based on context
 
Key Configuration Interface
 | interface DeployPageProps {
  offering: Offering;
  limits?: string[];
  updateMode?: boolean;
  previewMode?: boolean;
  order?: OrderResponse;
  plan?: Plan;
  initialLimits?: AttributesType;
  inputFormSteps: OfferingConfigurationFormStep[]; // Main configuration
}
  | 
 
Step Definition Structure
 | interface VStepperFormStep<T = VStepperFormStepProps> {
  label: string;                    // Display name
  id: string;                      // Unique identifier
  component: React.ComponentType<T>; // React component to render
  params?: Record<string, any>;    // Additional configuration
  fields?: Array<string>;          // Form fields managed by this step
  required?: boolean;              // Whether step is mandatory
  requiredFields?: Array<string>;  // Fields that must be completed
  isActive?: (data?: any) => boolean; // Dynamic step visibility
}
  | 
 
Usage Example: OpenstackInstanceOrder
 | // src/openstack/openstack-instance/OpenstackInstanceOrder.tsx
export const OpenstackInstanceOrder = (props) => (
  <BaseDeployPage inputFormSteps={deployOfferingSteps} {...props} />
);
  | 
 
Step Configuration:
 | // src/openstack/openstack-instance/deploy/steps.ts
export const deployOfferingSteps: OfferingConfigurationFormStep[] = [
  DetailsOverviewStep,           // Organization/Project selection
  FormCloudStep,                 // Cloud region (if shared offering)
  FormImageStep,                 // VM image selection
  FormHardwareConfigurationStep, // Flavor, storage configuration
  FormNetworkSecurityStep,       // Network and security groups
  FormStartupScriptStep,         // Automation/user data
  FormFinalConfigurationStep,    // Name, description
];
  | 
 
Common Implementation Pattern
All offering types follow the same pattern:
- Define Steps: Create array of 
OfferingConfigurationFormStep objects 
- Wrap BaseDeployPage: Pass steps as 
inputFormSteps prop 
- Register in Marketplace: Register in 
src/marketplace/common/registry.ts 
Other Examples:
OpenstackVolumeOrder - Volume deployment 
OpenstackTenantOrder - Tenant creation 
RancherOrderForm - Rancher cluster deployment 
RequestOrderForm - Support requests 
Key Features
Dynamic Step Filtering
 | const formSteps = useMemo(
  () =>
    inputFormSteps.filter(
      (step) => (step.isActive && step.isActive(selectedOffering)) ?? true,
    ),
  [selectedOffering],
);
  | 
 
Progressive Validation
- Tracks completed steps based on required field validation
 
- Uses scroll position to mark optional steps as "seen"
 
- Real-time validation feedback with error display
 
Multiple Operation Modes
- Create Mode: New resource deployment
 
- Update Mode: Editing existing orders with pre-populated values
 
- Preview Mode: Read-only display of form steps
 
Integration with Marketplace System
Registry Configuration
 | export const OpenStackInstanceOffering: OfferingConfiguration = {
  type: INSTANCE_TYPE,
  orderFormComponent: OpenstackInstanceOrder,
  detailsComponent: OpenstackInstanceDetails,
  checkoutSummaryComponent: CheckoutSummary,
  serializer: instanceSerializer,
  // ... other configuration
};
  | 
 
The DeployPageSidebar provides:
- Progress tracking with step completion status
 
- Error display for validation issues
 
- Checkout summary with pricing information
 
- Order summary customizable per offering type
 
Best Practices
- Consistent Step Structure: All offering types use the same step interface
 
- Lazy Loading: Components are lazy-loaded for better performance
 
- Type Safety: Strong TypeScript typing throughout
 
- Reusable Components: Common steps like 
DetailsOverviewStep are shared 
- Error Handling: Comprehensive validation and error display
 
- Accessibility: Proper ARIA labels and keyboard navigation
 
The BaseDeployPage component represents a well-architected, reusable foundation that allows different cloud services to implement their specific deployment workflows while maintaining consistency across the marketplace experience.
The application uses a sophisticated type-based field selection system for creating dynamic Redux forms, exemplified by the SupportSettingsForm.tsx component.
Core Pattern: Dynamic Field Selection
The primary pattern uses a FieldRow component that selects appropriate field types based on configuration:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21  | const FieldRow = ({ field, ...rest }) =>
  field.type === 'string' ? (
    <StringField {...rest} />
  ) : field.type === 'boolean' ? (
    <AwesomeCheckboxField
      label={getKeyTitle(field.key)}
      hideLabel
      className="mt-3"
      {...rest}
    />
  ) : field.type === 'email_field' ? (
    <EmailField {...rest} />
  ) : field.type === 'text_field' ? (
    <TextField {...rest} />
  ) : field.type === 'integer' ? (
    <NumberField {...rest} />
  ) : field.type === 'secret_field' ? (
    <SecretField {...rest} />
  ) : (
    <StringField {...rest} />
  );
  | 
 
Field Type System
The application supports these field types:
string - Basic text input using StringField 
boolean - Checkbox using AwesomeCheckboxField 
email_field - Email input with validation using EmailField 
text_field - Multi-line text using TextField 
integer - Numeric input using NumberField 
secret_field - Password/secret input using SecretField 
All fields are wrapped with Redux Form's Field component and FormGroup:
 | <Field
  component={FormGroup}
  name={field.key}
  key={field.key}
  label={field.description}
>
  <FieldRow field={field} />
</Field>
  | 
 
All field components extend the FormField interface for consistent props:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20  | export interface FormField {
  name?: string;
  input?: WrappedFieldInputProps;
  meta?: WrappedFieldMetaProps;
  required?: boolean;
  label?: ReactNode;
  description?: ReactNode;
  tooltip?: ReactNode;
  validate?: Validator | Validator[];
  disabled?: boolean;
  hideLabel?: boolean;
  normalize?: Normalizer;
  format?: Formatter | null;
  parse?: Parser;
  noUpdateOnBlur?: boolean;
  onBlur?(e): void;
  containerClassName?: string;
  spaceless?: boolean;
  readOnly?: boolean;
}
  | 
 
Forms are generated from configuration objects:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20  | export const SupportSettingsForm = ({ name }) => {
  const fields = SettingsDescription.find((group) =>
    group.description.toLowerCase().includes(name),
  ).items;
  return (
    <>
      {fields.map((field) => (
        <Field
          component={FormGroup}
          name={field.key}
          key={field.key}
          label={field.description}
        >
          <FieldRow field={field} />
        </Field>
      ))}
    </>
  );
};
  | 
 
Field Configuration Structure
 | {
  key: 'FIELD_NAME',
  description: 'Field description',
  default: 'default_value',
  type: 'string' | 'boolean' | 'integer' | 'email_field' | 'text_field' | 'secret_field'
}
  | 
 
Advanced Field Factory Pattern
For more complex scenarios, the system uses a comprehensive field factory:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16  | const getFieldComponent = useCallback((field, index, { key, ...props }) => {
  if (field.component) {
    return <field.component key={key} {...props} {...(field.extraProps || {})} />;
  } else if (field.type === 'string') {
    return <StringField key={key} {...props} validate={field.validate} />;
  } else if (field.type === 'json') {
    return <MonacoField key={key} {...props} language="json" validate={validateJSON} />;
  } else if (field.type === 'datetime') {
    return <DateTimeField key={key} {...props} />;
  } else if (field.type === 'select') {
    return <SelectField key={key} {...props} options={field.options} />;
  } else if (field.type === 'async_select') {
    return <AsyncSelectField key={key} {...props} {...field.extraProps} />;
  }
  // ... other field types
}, []);
  | 
 
Validation and Error Handling
The system provides comprehensive validation through:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12  | // Core validators
export const required = (value) =>
  value || value === 0 ? undefined : translate('This field is required.');
export const email = (value) =>
  value && !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)
    ? translate('Invalid email address')
    : undefined;
// Validator composition
export const composeValidators = (...validators) => (value) =>
  validators.reduce((error, validator) => error || validator(value), undefined);
  | 
 
- Consistent Type Strings: Use standardized type identifiers across field configurations
 
- Fallback Strategy: Always provide a default field type (typically 
StringField) 
- Props Interface: Extend the base 
FormField interface for type safety 
- Validator Composition: Use 
composeValidators for complex validation logic 
- Error Handling: Integrate with Redux Form's meta.touched state for error display
 
- Configuration-Driven: Use data structures to define forms rather than hardcoding
 
This type-specific field system enables dynamic form generation while maintaining type safety and consistent user experience across the application.