Frontend

Component Patterns

Detailed exploration of Studio's key component patterns for building scalable analytics interfaces.

Overview

Studio implements several proven component patterns that enable developers to build consistent, maintainable analytics interfaces. These patterns provide reusable abstractions for common functionality.

Key component patterns used throughout Studio

Builder Components

Builder components enable complex form configuration through modular, composable interfaces.

Metric Schema Builder

The most complex builder pattern in Studio, orchestrating multiple sub-builders for metric configuration.

How MetricSchemaBuilder coordinates sub-builders

Architecture:

  • Tabbed Interface: Organizes complex configuration into manageable sections
  • Reactive Schema: Shared reactive schema object across all builders
  • Validation Integration: Real-time validation with visual feedback
  • Preview Mode: Live preview of metric configuration

Key Sub-Builders:

  • BasicInfoBuilder - Core metric information (name, description, table)
  • MeasuresBuilder - Quantitative measurements and calculations
  • DimensionsBuilder - Categorical attributes for grouping
  • JoinsBuilder - Table relationship definitions
  • FiltersBuilder - Data filtering conditions
  • AggregationsBuilder - Complex aggregation logic
  • ParametersBuilder - Runtime parameter configuration

Implementation Pattern:

// Shared reactive schema
const schema = reactive({
  name: '',
  description: '',
  measures: [],
  dimensions: [],
  joins: [],
  filters: [],
  aggregations: [],
  parameters: {}
})

// Each builder receives the schema section it manages
<MeasuresBuilder v-model="schema.measures" />
<DimensionsBuilder v-model="schema.dimensions" />

Dashboard Builder

Enables visual dashboard composition with drag-and-drop functionality.

Dashboard building workflow and component structure

Components:

  • DashboardContainer - Main dashboard layout and orchestration
  • DashboardSection - Grouped widget areas with drag-and-drop
  • WidgetRenderer - Dynamic widget component rendering
  • WidgetEditSheet - Widget configuration interface
  • DataMappingEditor - Chart data mapping configuration

Features:

  • Grid Layout: Responsive grid system for widget positioning
  • Drag & Drop: FormKit drag-and-drop for widget arrangement
  • Real-time Preview: Live dashboard execution and preview
  • Widget Library: Extensible widget type system

Dialog Patterns

Consistent modal interfaces for all CRUD operations across Studio.

Standard CRUD Dialogs

Standardized create, edit, and delete dialog patterns

Dialog Types:

Create Dialogs

  • CreateWorkspaceDialog - New workspace creation
  • CreateEnvironmentDialog - Environment setup
  • CreateDataSourceDialog - Data source configuration
  • CreateMetricDialog - Basic metric creation
  • CreateConsumerDialog - Consumer management

Pattern:

// Consistent structure for create dialogs
interface CreateDialogProps {
  open: boolean
  prefilledData?: Partial<T>
}

interface CreateDialogEmits {
  'update:open': (value: boolean) => void
  'created': (item: T) => void
}

Edit Dialogs

  • EditWorkspaceDialog - Workspace modification
  • EditEnvironmentDialog - Environment updates
  • EditDataSourceDialog - Data source changes
  • EditMetricDialog - Metric modifications

Pattern:

// Edit dialogs include item identification
interface EditDialogProps {
  open: boolean
  item: T
}

interface EditDialogEmits {
  'update:open': (value: boolean) => void
  'updated': (item: T) => void
}

Complex Dialogs

Advanced dialogs for multi-step workflows.

Multi-step dialog patterns for complex workflows

Examples:

  • MetricDialog - Full metric creation with schema builder
  • WidgetUpsertDialog - Widget creation with chart configuration
  • DashboardViewSelector - Dashboard view management

Features:

  • Multi-step Flows: Tabbed or wizard-style interfaces
  • Form Validation: Comprehensive validation with error display
  • Auto-save: Draft saving for complex configurations
  • Help Context: Contextual help and examples

Chart Component Patterns

Reusable visualization components with consistent APIs.

Base Chart Pattern

Base chart component structure and inheritance

Chart Types:

  • BarChart - Bar and column charts
  • LineChart - Line and area charts
  • DonutChart - Pie and donut charts
  • Gauge - Gauge and KPI displays
  • SingleValue - Single metric displays
  • Table - Data table with sorting

Common Interface:

interface BaseChartProps {
  data: any[]
  height: number
  config?: ChartConfig
  loading?: boolean
}

interface ChartConfig {
  colors?: string[]
  legend?: boolean
  grid?: boolean
  responsive?: boolean
}

Chart Selector Pattern

Dynamic chart type selection with automatic data mapping.

How ChartSelector enables dynamic chart type switching

Features:

  • Type Detection: Automatic chart type recommendations
  • Field Mapping: Smart field mapping for X/Y axes
  • Data Validation: Real-time validation of chart compatibility
  • Preview Mode: Instant chart preview with configuration changes

Widget Pattern

Dashboard widgets that wrap charts with additional functionality.

Widget wrapper pattern for dashboard integration

Widget Types:

  • ChartWidget - Standard chart visualizations
  • SingleValueWidget - KPI and metric displays
  • GaugeWidget - Progress and target visualizations
  • TableWidget - Data table displays

Widget Features:

  • Metric Integration: Direct metric execution and display
  • Configuration UI: Built-in configuration interfaces
  • Error Handling: Graceful error display and recovery
  • Loading States: Skeleton loading for better UX

Form Patterns

Consistent form handling with validation and error management.

Validated Forms

Form validation pattern with VeeValidate and Zod

Implementation:

  • Schema Validation: Zod schemas for type-safe validation
  • Real-time Feedback: Immediate validation on field changes
  • Error Display: Consistent error message presentation
  • Field Dependencies: Cross-field validation and dependencies

Example Pattern:

// Form schema definition
const formSchema = z.object({
  name: z.string().min(1, 'Name is required'),
  description: z.string().optional(),
  type: z.enum(['bar', 'line', 'pie'])
})

// Form state management
const { values, errors, isValid } = useForm({
  validationSchema: toTypedSchema(formSchema)
})

Field Mapping Forms

Specialized forms for mapping data fields to chart properties.

Field mapping form pattern for chart configuration

Components:

  • FieldMappingSelector - Field selection with type detection
  • DataMappingEditor - Complete data mapping configuration
  • ColumnSelector - Column selection from data sources

Features:

  • Auto-detection: Automatic field type detection
  • Validation: Field compatibility validation
  • Preview: Real-time mapping preview
  • Suggestions: Smart field mapping suggestions

Layout Patterns

Consistent layout patterns for different page types.

Main application layout with navigation sidebar

Components:

  • Sidebar - Main navigation with workspace context
  • SidebarHeader - Logo and global controls
  • SidebarContent - Navigation menu and workspace selector
  • SidebarMenu - Primary navigation items

Features:

  • Context Switching: Workspace and environment selection
  • Responsive Design: Collapsible sidebar for mobile
  • Theme Toggle: Light/dark mode switching
  • Route Highlighting: Active route indication

Page Layout

Standard page layout pattern for consistent spacing and structure.

Standard page layout structure and spacing

Elements:

  • Page Header: Title, description, and primary actions
  • Content Area: Main page content with consistent spacing
  • Action Bars: Secondary actions and filters
  • Loading States: Skeleton layouts during data loading

Consistent modal and overlay patterns.

Modal layout patterns for different dialog types

Types:

  • Standard Modals: Basic dialog interfaces
  • Full-screen Modals: Complex configuration interfaces
  • Slide-out Panels: Secondary information displays
  • Confirmation Dialogs: Simple confirmation interfaces

State Patterns

Patterns for managing component state and reactivity.

Composable State

How components integrate with composable state

Pattern:

// Component using composable state
const { 
  items, 
  loading, 
  error, 
  fetchItems, 
  createItem, 
  updateItem, 
  deleteItem 
} = useMetrics()

// Reactive state automatically updates component
watchEffect(() => {
  if (selectedWorkspace.value) {
    fetchItems(selectedWorkspace.value.id)
  }
})

Local State Management

Local component state management patterns

Guidelines:

  • Reactive Refs: Use ref() for primitive values
  • Reactive Objects: Use reactive() for complex objects
  • Computed Properties: Derive state with computed()
  • Watchers: Handle side effects with watch() and watchEffect()

Error Handling Patterns

Consistent error handling and user feedback patterns.

Error Display

Error handling and user feedback patterns

Error Types:

  • Validation Errors: Form field validation feedback
  • API Errors: Network and server error handling
  • Component Errors: Component-level error boundaries
  • Loading Errors: Failed data loading scenarios

Display Patterns:

  • Inline Errors: Field-level validation errors
  • Toast Notifications: Global success/error messages
  • Error States: Component error state displays
  • Retry Mechanisms: User-initiated error recovery

Best Practices

Component Design

  1. Single Responsibility: Each component should have one clear purpose
  2. Props Interface: Use TypeScript interfaces for all props
  3. Event Emission: Emit events for parent component communication
  4. Slot Utilization: Provide slots for flexible content injection
  5. Accessibility: Include ARIA labels and keyboard navigation

Performance Optimization

  1. Lazy Loading: Load components only when needed
  2. Computed Caching: Use computed properties for expensive operations
  3. Event Debouncing: Debounce user input for API calls
  4. Memory Management: Clean up watchers and event listeners
  5. Bundle Splitting: Split large components for better loading

Reusability

  1. Generic Interfaces: Design components for reuse across contexts
  2. Configuration Props: Provide props for customization
  3. Composable Logic: Extract business logic to composables
  4. Style Variants: Support different visual styles via props
  5. Extension Points: Provide hooks for extending functionality

Next Steps

These component patterns provide the foundation for building consistent, maintainable analytics interfaces that scale with your application needs.