# Metrics Review (`metrics-01`) - SignalOS page block

> Full-page metrics and baseline review block. Displays AI-generated monitoring metrics with SQL/API/cross-source formulas, baseline configuration, and batch progress tracking.

- **Version:** 0.5.5
- **Kind:** block (group: semantics-details) · **Category:** pages
- **Install:** `npx shadcn@latest add @signalos/metrics-01`
- **Registry dependencies (pulled automatically):** @signalos/tokens, @signalos/utils, @signalos/button, @signalos/badge, @signalos/dialog, @signalos/select, @signalos/checkbox, @signalos/input, @signalos/label, @signalos/tooltip, @signalos/textarea, @signalos/split-panel
- **npm dependencies:** lucide-react@^0.462.0
- **Files installed:** `src/components/blocks/metrics-01/MetricsReview.tsx`, `src/components/blocks/metrics-01/components/MetricAddDialog.tsx`, `src/components/blocks/metrics-01/Metrics.types.ts`, `src/components/blocks/metrics-01/Metrics.utils.ts`, `src/components/blocks/metrics-01/components/BaselineConfigPanel.tsx`, `src/components/blocks/metrics-01/components/BatchProgressBanner.tsx`, `src/components/blocks/metrics-01/components/MetricQueueList.tsx`, `src/components/blocks/metrics-01/components/MetricDetailView.tsx`, `src/components/blocks/metrics-01/components/MetricEditForm.tsx`, `src/components/blocks/metrics-01/components/MetricBasicFields.tsx`, `src/components/blocks/metrics-01/components/MetricCompositeActions.tsx`, `src/components/blocks/metrics-01/components/MetricSqlEditor.tsx`, `src/components/blocks/metrics-01/components/MetricApiActionEditor.tsx`, `src/components/blocks/metrics-01/components/MetricTypeSelector.tsx`, `src/components/blocks/metrics-01/components/MetricSqlFields.tsx`, `src/components/blocks/metrics-01/components/MetricApiFields.tsx`, `src/components/blocks/metrics-01/components/MetricCrossSourceFields.tsx`, `src/components/blocks/metrics-01/components/MetricsPageHeader.tsx`, `src/components/blocks/metrics-01/components/MetricDetailPanel.tsx`

## Access

This is a private registry: pulling source requires a `SIGNALOS_REGISTRY_TOKEN`
(GitHub fine-grained PAT with read access to the signal-widgets repo) and an
`@signalos` entry in components.json `"registries"`. Previews and this document are public.

## Usage

```tsx
// after: npx shadcn@latest add @signalos/metrics-01
// mount the pulled page in a route, e.g. src/app/semantics-details/page.tsx
import MetricsReview from "@/components/blocks/metrics-01/MetricsReview"

export default function Page() {
  return <MetricsReview />
}
```

## Props

### `MetricDirection`

```ts
export type MetricDirection = "up_is_good" | "down_is_good" | "neutral"
```

### `MetricValidationStatus`

```ts
export type MetricValidationStatus = "validated" | "healed" | "failed"
```

### `BaselineWindow`

```ts
export type BaselineWindow = "7d" | "30d" | "90d" | "6mo" | "1y" | "all"
```

### `MetricActionType`

```ts
export type MetricActionType = "sql" | "api" | "cross_source"
```

### `MetricUnit`

```ts
export type MetricUnit =
  | "count"
  | "percent"
  | "percentage"
  | "ratio"
  | "rate"
  | "currency"
  | "index"
  | "seconds"
  | "minutes"
  | "hours"
  | "days"
  | "months"
  | "years"
  | "score"
  | "bytes"
```

### `CompositeAction`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `connector_id` | `string \| undefined` | no | - |  |
| `action_sql` | `string \| undefined` | no | - |  |
| `sql` | `string \| undefined` | no | - |  |
| `label` | `string \| undefined` | no | - |  |
| `result_label` | `string \| undefined` | no | - |  |
| `result_value` | `string \| number \| null \| undefined` | no | - |  |
| `action` | `string \| undefined` | no | - |  |
| `resource` | `string \| undefined` | no | - |  |
| `filter_field` | `string \| undefined` | no | - |  |
| `filter_value` | `string \| undefined` | no | - |  |
| `extract_field` | `string \| undefined` | no | - |  |
| `action_input` | `Record<string, unknown> \| undefined` | no | - |  |
| `ratio` | `unknown` | no | - |  |
| `computation` | `unknown` | no | - |  |
| `expected_result_type` | `string \| undefined` | no | - |  |

### `MetricActionInput`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `sql` | `string \| undefined` | no | - |  |
| `action` | `string \| undefined` | no | - |  |
| `resource` | `string \| undefined` | no | - |  |
| `connector_id` | `string \| undefined` | no | - |  |
| `filter_field` | `string \| undefined` | no | - |  |
| `filter_value` | `string \| undefined` | no | - |  |
| `extract_field` | `string \| undefined` | no | - |  |
| `action_input` | `Record<string, unknown> \| undefined` | no | - |  |
| `result_label` | `string \| undefined` | no | - |  |
| `result_value` | `string \| number \| null \| undefined` | no | - |  |

### `MetricFormulaAction`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `action` | `string \| undefined` | no | - |  |
| `resource` | `string \| undefined` | no | - |  |
| `input` | `{ [key: string]: unknown; sql?: string \| undefined; action_a?: MetricActionInput \| undefined; action_b?: MetricActionInput \| undefined; } \| undefined` | no | - |  |
| `filter_field` | `string \| undefined` | no | - |  |
| `filter_value` | `string \| undefined` | no | - |  |
| `extract_field` | `string \| undefined` | no | - |  |
| `expected_result_type` | `string \| undefined` | no | - |  |
| `ratio` | `unknown` | no | - |  |

### `MetricComputation`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `expression` | `string \| undefined` | no | - |  |

### `SemanticMetric`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `metric_name` | `string` | yes | - |  |
| `display_name` | `string \| undefined` | no | - |  |
| `description` | `string \| undefined` | no | - |  |
| `unit` | `string \| undefined` | no | - |  |
| `direction` | `MetricDirection \| undefined` | no | - |  |
| `current_value` | `string \| number \| null \| undefined` | no | - |  |
| `baseline_value` | `number \| null \| undefined` | no | - |  |
| `baseline_stddev` | `number \| null \| undefined` | no | - |  |
| `baseline_deviation` | `number \| null \| undefined` | no | - |  |
| `baseline_window` | `BaselineWindow \| undefined` | no | - |  |
| `baseline_alpha` | `number \| undefined` | no | - |  |
| `baseline_sample_count` | `number \| undefined` | no | - |  |
| `baseline_source` | `string \| undefined` | no | - |  |
| `baseline_sql` | `string \| undefined` | no | - |  |
| `validation_status` | `MetricValidationStatus \| undefined` | no | - |  |
| `validation_error` | `string \| undefined` | no | - |  |
| `confidence` | `number \| undefined` | no | - |  |
| `is_anomalous` | `boolean \| undefined` | no | - |  |
| `is_cross_source` | `boolean \| undefined` | no | - |  |
| `cross_cluster` | `boolean \| undefined` | no | - |  |
| `source_cluster` | `string \| undefined` | no | - |  |
| `formula_action` | `MetricFormulaAction \| undefined` | no | - |  |
| `formula_human` | `string \| undefined` | no | - |  |
| `source_entities` | `string[] \| undefined` | no | - |  |
| `composite_actions` | `CompositeAction[] \| undefined` | no | - |  |
| `computation` | `string \| MetricComputation \| undefined` | no | - |  |
| `metric_type` | `string \| undefined` | no | - |  |
| `reasoning` | `string \| undefined` | no | - |  |
| `join_paths` | `{ from_table: string; from_column: string; to_table: string; to_column: string; join_type: string; }[] \| undefined` | no | - |  |
| `bridge_used` | `string \| undefined` | no | - |  |
| `signal_candidates` | `string[] \| undefined` | no | - |  |
| `related_metrics` | `string[] \| undefined` | no | - |  |
| `action_type` | `MetricActionType \| undefined` | no | - |  |
| `formula_sql` | `string \| undefined` | no | - |  |
| `review_origin` | `string \| undefined` | no | - |  |

### `MetricReviewItem`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `index` | `number` | yes | - |  |
| `status` | `"accepted" \| "flagged" \| "deleted"` | yes | - |  |
| `feedback` | `string` | yes | - |  |
| `edits` | `Partial<SemanticMetric>` | yes | - |  |

### `MetricReviewDecision`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `status` | `"accepted" \| "flagged"` | yes | - |  |
| `feedback` | `string` | yes | - |  |
| `edits` | `Partial<SemanticMetric>` | yes | - |  |

### `SqlTestResult`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `status` | `"success" \| "error" \| "loading" \| "idle"` | yes | - |  |
| `result` | `unknown` | no | - |  |
| `baselineValue` | `number \| null \| undefined` | no | - |  |
| `error` | `string \| undefined` | no | - |  |

### `MetricItemEdits`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `metric_name` | `string` | yes | - |  |
| `display_name` | `string \| undefined` | no | - |  |
| `description` | `string \| undefined` | no | - |  |
| `unit` | `string \| undefined` | no | - |  |
| `direction` | `MetricDirection \| undefined` | no | - |  |
| `note` | `string \| undefined` | no | - |  |
| `action_type` | `MetricActionType \| undefined` | no | - |  |
| `formula_sql` | `string \| undefined` | no | - |  |
| `formula_action` | `Record<string, unknown> \| MetricFormulaAction \| undefined` | no | - |  |
| `is_cross_source` | `boolean \| undefined` | no | - |  |
| `composite_actions` | `Record<string, unknown>[] \| undefined` | no | - |  |
| `computation` | `Record<string, unknown> \| undefined` | no | - |  |

### `SubmitMetricsReviewPayload`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `action` | `"confirm" \| "retry"` | yes | - |  |
| `items` | `MetricReviewItem[] \| undefined` | no | - |  |

### `CreateSemanticMetricPayload`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `metric_name` | `string` | yes | - |  |
| `display_name` | `string \| undefined` | no | - |  |
| `description` | `string \| undefined` | no | - |  |
| `unit` | `string \| undefined` | no | - |  |
| `direction` | `MetricDirection \| undefined` | no | - |  |
| `formula_action` | `MetricFormulaAction \| undefined` | no | - |  |

### `AddMetricPayload`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `action` | `"add_item" \| "improve_new_item"` | yes | - |  |
| `connector_id` | `string` | yes | - |  |
| `feedback` | `string \| undefined` | no | - |  |
| `item_edits` | `MetricItemEdits` | yes | - |  |

### `AddMetricResponse`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `item` | `SemanticMetric \| undefined` | no | - |  |
| `soft_warning` | `string \| undefined` | no | - |  |

### `BaselineConfig`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `window` | `BaselineWindow` | yes | - |  |
| `alpha` | `number` | yes | - |  |
| `date_column_preference` | `string \| undefined` | no | - |  |

### `MetricsBatchInfo`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `batch_num` | `number` | yes | - |  |
| `total_batches` | `number` | yes | - |  |
| `metrics_in_batch` | `number` | yes | - |  |
| `all_batches_complete` | `boolean \| undefined` | no | - |  |

### `MetricsFdeInput`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `items` | `MetricReviewItem[]` | yes | - |  |

### `MetricSqlTestResult`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `status` | `"success" \| "error"` | yes | - |  |
| `metric_name` | `string \| undefined` | no | - |  |
| `current_value` | `string \| number \| null \| undefined` | no | - |  |
| `baseline_value` | `number \| null \| undefined` | no | - |  |
| `validation_status` | `string \| undefined` | no | - |  |
| `validation_error` | `string \| undefined` | no | - |  |
| `sql` | `string \| undefined` | no | - |  |

### `MetricCatalogEntry`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `display_name` | `string \| undefined` | no | - |  |
| `description` | `string \| undefined` | no | - |  |
| `direction` | `MetricDirection \| undefined` | no | - |  |
| `unit` | `string \| undefined` | no | - |  |
| `connector_id` | `string \| undefined` | no | - |  |
| `source_cluster` | `string \| undefined` | no | - |  |
| `is_cross_source` | `boolean \| undefined` | no | - |  |
| `source_entities` | `string[] \| undefined` | no | - |  |
| `sql_logic` | `string \| undefined` | no | - |  |

### `MetricCatalog`

```ts
export type MetricCatalog = Record<string, MetricCatalogEntry>
```

### `MetricAddFormCompositeAction`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `result_label` | `string` | yes | - |  |
| `kind` | `"sql" \| "api"` | yes | - |  |
| `connector_id` | `string` | yes | - |  |
| `body` | `string` | yes | - |  |

### `MetricAddFormState`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `type` | `MetricActionType` | yes | - |  |
| `metric_name` | `string` | yes | - |  |
| `display_name` | `string` | yes | - |  |
| `description` | `string` | yes | - |  |
| `unit` | `string` | yes | - |  |
| `direction` | `MetricDirection` | yes | - |  |
| `note` | `string` | yes | - |  |
| `aiNote` | `string` | yes | - |  |
| `sqlConnectorId` | `string` | yes | - |  |
| `sql` | `string` | yes | - |  |
| `apiConnectorId` | `string` | yes | - |  |
| `formulaAction` | `string` | yes | - |  |
| `composite` | `MetricAddFormCompositeAction[]` | yes | - |  |
| `expression` | `string` | yes | - |  |
| `method` | `string` | yes | - |  |
| `interpretation` | `string` | yes | - |  |

### `MetricAddFormErrors`

```ts
export type MetricAddFormErrors = Partial<
  Record<keyof MetricAddFormState | "composite", string>
>
```

### `ActionState`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `loading` | `boolean \| undefined` | no | - |  |
| `value` | `unknown` | no | - |  |
| `error` | `string \| undefined` | no | - |  |

### `MetricDetailViewProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `selectedMetric` | `SemanticMetric` | yes | - |  |
| `sqlTestResults` | `Record<number, SqlTestResult>` | yes | - |  |
| `actionResults` | `Record<number, { a?: ActionState \| undefined; b?: ActionState \| undefined; }>` | yes | - |  |
| `selectedMetricIdx` | `number` | yes | - |  |
| `copiedSql` | `boolean` | yes | - |  |
| `expandedSql` | `Record<number, boolean>` | yes | - |  |
| `onCopySql` | `(sql: string) => void` | yes | - |  |
| `onExecuteMetric` | `(idx: number) => void` | yes | - |  |
| `onExecuteAction` | `(idx: number, side: "a" \| "b") => void` | yes | - |  |
| `onExecuteBothActions` | `(idx: number) => void` | yes | - |  |

## Changelog

## 0.5.5
- Lint issues resolved
## 0.5.4

- Decompose `MetricsReview` into `MetricDetailPanel`, `MetricsPageHeader`, `MetricAddDialog`, `MetricEditForm`, `MetricQueueList`, and `MetricDetailView` subcomponents.
- Extract field groups into `MetricBasicFields`, `MetricApiFields`, `MetricSqlFields`, `MetricCrossSourceFields`; extract `MetricApiActionEditor`, `MetricSqlEditor`, `MetricCompositeActions`, and `MetricTypeSelector`.

## 0.5.3

- Replace raw scale token classes with semantic tokens (text-text-error, bg-bg-success, border-border-warning, etc.) to respect client theme overrides.

## 0.5.2

- Fix file casing: rename Metrics.types.ts to match PascalCase import paths.

## 0.5.1

- Change onSetEditedSql and onSetEditedCompositeSql prop types from React.Dispatch<SetStateAction<...>> to plain value callbacks, removing the leaked setter type from the public API.

## 0.4.1
## 0.4.0

- Replace `grid grid-cols-1 lg:grid-cols-12` layout with `SplitPanel` widget for the queue/detail split.
- Add `@signalos/split-panel` to `registryDependencies`.

## 0.3.0

- Refactor: lift all form state, validation, composite action mutations, and async submit logic out of `MetricAddDialog` into `MetricsReview` (parent).
- `MetricAddDialog` is now fully presentational — receives controlled `form`, `errors`, `formError`, `activeTypeDesc`, and individual change/submit callbacks as props.
- Extract `getCompositeActions` helper to `Metrics.utils.ts`; `MetricDetailView` and `MetricEditForm` now import it instead of duplicating the derivation inline.
- Added `MetricAddFormState`, `MetricAddFormCompositeAction`, `MetricAddFormErrors` to `metrics.types.ts`.

## 0.2.0

- **Breaking:** Remove `pipelineId` prop — was unused internally.
- **Breaking:** `MetricAddDialog` now exports `ConnectorLike` instead of re-importing `ConnectorConfig` from `semantics-details-01`; callers only need `{ connector_id: string }`.
- Fix `registry-item.json` files list — was incorrectly pointing at `cross-source-01` paths.
- Fix description and `lucide-react` version range in manifest; add missing `@signalos/textarea` dep.
- Replace raw palette tokens (`error-*`, `success-*`, `info-*`, `navy-*`) with semantic tokens throughout `MetricsReview.tsx` and `MetricAddDialog.tsx`.
- Add `note` field to `MetricItemEdits` to match what `MetricAddDialog` submits.
- Remove dead `handleImproveWithAi` function and `isImproving` state.

## 0.1.0

Initial release.
