Skip to main content

Types and Patterns

Key TypeScript Types

Phase

The Phase enum represents different stages in the ML workflow. Phases are used in URL routing and define the application's navigation structure.

export enum Phase {
Project = 'project',
Data = 'data',
Train = 'train',
Retrain = 'retrain',
Deploy = 'deploy',
Monitor = 'monitor',
// GenAI workflow
GenaiLLM = 'genai-llm',
GenaiData = 'genai-data',
GenaiPrompt = 'genai-prompt',
GenaiFinetune = 'genai-finetune',
GenaiMonitor = 'genai-monitor',
// Agent workflow
AgentData = 'agent-data',
AgentDevelop = 'agent-develop',
AgentDeploy = 'agent-deploy',
AgentMonitor = 'agent-monitor',
}

PhaseConfig

PhaseConfig defines a workflow phase's appearance and entities:

export interface PhaseConfig {
id: string; // URL segment
icon: string; // Icon name from IconProvider
name: string; // Display name (e.g., "Train & Evaluate")
description?: string; // Optional description
docUrl?: string; // Link to documentation
state: PhaseState; // 'active' | 'comingSoon' | 'disabled'
entities: PhaseEntityConfig[];
}

PhaseEntityConfig

PhaseEntityConfig defines an entity within a phase:

export interface PhaseEntityConfig<T extends object = object> {
name: string; // Display name (plural, lowercase): "trained models"
id: string; // URL segment (plural, no whitespace): "models"
service: string; // RPC service name: "pipeline", "pipelineRun"
state: PhaseEntityState; // 'active' | 'disabled'
views: ViewConfig<T>[]; // List and detail view configurations
actions?: React.ComponentType<{ record: T }>;
}

ViewConfig

ViewConfig defines how an entity is displayed:

export type ViewConfig<T> = ListViewConfig<T> | DetailViewConfig<T>;

export interface ListViewConfig<T> {
type: 'list';
tableConfig: TableConfig<T>;
}

export interface DetailViewConfig<T> {
type: 'detail';
metadata: Cell[];
pages: DetailPageConfig<T>[];
}

Accessor

A flexible way to access object properties, supporting both dot-notation strings and functions:

export type Accessor<K = unknown> = AccessorFn<K> | string;
export type AccessorFn<T = unknown> = (object: unknown) => T | undefined;

// Examples
const accessor1: Accessor = 'metadata.name';
const accessor2: Accessor = 'users[0].email';
const accessor3: Accessor<string> = (obj) => obj.user?.name;

Type Conventions

Naming

PatternExampleUsage
PascalCasePhaseConfig, ViewConfigTypes and interfaces
No T suffixTableData not TTableDataGeneric type parameters
SingularColumnConfigType names
Pluralcolumns: ColumnConfig[]Array properties

Props Types

Follow the pattern established in each component area:

// Simple "Props" when single component per file
interface Props {
data: TableData[];
columns: ColumnConfig[];
}

// "ComponentNameProps" when multiple components or exported
export interface TableCellProps<T> {
column: ColumnConfig<T>;
record: object;
value: T | undefined;
}

State Types

Use union types for finite states:

export type PhaseState = 'active' | 'comingSoon' | 'disabled';
export type PhaseEntityState = 'active' | 'disabled';
export type TableViewState = 'loading' | 'empty' | 'ready' | 'error' | 'filtered-empty';

React Component Patterns

Functional Components

All components use functional components with hooks:

export function Table<T extends TableData>({ data, columns }: TableProps<T>) {
const [css] = useStyletron();
// ...
}

Props Naming

Event handlers focus on intent rather than event type:

// Preferred
const showTooltipAfterDelay = () => { /* ... */ };
const toggleMenu = () => { /* ... */ };

// Avoid
const handleOnMouseEnter = () => { /* ... */ };
const handleOnClick = () => { /* ... */ };

Generic Components

Components accepting data use generic type parameters:

interface TableProps<T extends TableData = TableData> {
data: T[];
columns: ColumnConfig<T>[];
}

export function Table<T extends TableData>(props: TableProps<T>) {
// T is inferred from data
}

File and Naming Conventions

File Names

  • Use kebab-case: use-studio-query.ts, table-cell.tsx
  • Use .tsx for files with JSX, .ts otherwise
  • Tests go in __tests__/ directories: __tests__/use-studio-query.test.ts

Directory Structure

Components follow a recursive folder structure:

components/
├── table/
│ ├── components/
│ │ ├── table-header/
│ │ ├── table-body/
│ │ └── table-cell/
│ ├── hooks/
│ ├── types/
│ ├── utils/
│ └── table.tsx

Import Style

Prefer direct imports over barrel exports:

// Preferred
import { useStudioQuery } from '#core/hooks/use-studio-query';

// Avoid index re-exports
import { useStudioQuery } from '#core/hooks';