Atlas / Skills / getsentry / Migrate Frontend Forms

Migrate Frontend FormsCAUTION

skills/getsentry/migrate-frontend-forms

Developer-first error tracking and performance monitoring

Verdict
CAUTION
Grade
B
Trust score
89 /100
Version
—
Hosts
—
License
NOASSERTION
Stars
44,873
01

Overview

Developer-first error tracking and performance monitoring

Read from source at commit 42a3375c14f5OBSERVED · 2026-09-29
02

What it tells the agent

The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.

---
name: migrate-frontend-forms
description: Guide for migrating forms from the legacy JsonForm/FormModel system to the new TanStack-based form system.
---

# Form Migration Guide

This skill helps migrate forms from Sentry's legacy form system (JsonForm, FormModel) to the new TanStack-based system.

## Feature Mapping

| Old System           | New System            | Notes                                                |
| -------------------- | --------------------- | ---------------------------------------------------- |
| `saveOnBlur: true`   | `AutoSaveForm`        | Default behavior                                     |
| `confirm`            | `confirm` prop        | `string \| ((value) => string \| undefined)`         |
| `showHelpInTooltip`  | `variant="compact"`   | On layout components                                 |
| `disabledReason`     | `disabled="reason"`   | String shows tooltip                                 |
| `extraHelp`          | JSX in layout         | Render `<Text>` below field                          |
| `getData`            | `mutationFn`          | Transform data in mutation function                  |
| `mapFormErrors`      | Request error adapter | Explicit for regular forms; provided for auto-save   |
| `saveMessage`        | `onSuccess`           | Show toast in mutation onSuccess callback            |
| `formatMessageValue` | `onSuccess`           | Control toast content in onSuccess callback          |
| `resetOnError`       | `onError`             | Call form.reset() in mutation onError                |
| `saveOnBlur: false`  | `useScrapsForm`       | Use regular form with explicit Save button           |
| (automatic)          | `form.reset()`        | Call after successful mutation if form stays on page |
| `help`               | `hintText`            | On layout components                                 |
| `label`              | `label`               | On layout components                                 |
| `required`           | `required`            | On layout + Zod schema                               |

## Feature Details

### confirm → `confirm` prop

**Old:**

```tsx
{
  name: 'require2FA',
  type: 'boolean',
  confirm: {
    true: 'Enable 2FA for all members?',
    false: 'Allow members without 2FA?',
  },
  isDangerous: true,
}
```

**New:**

```tsx
<AutoSaveForm
  name="require2FA"
  confirm={value =>
    value
      ? 'Enable 2FA for all members?'
      : 'Allow members without 2FA?'
  }
  {...}
>
```

### showHelpInTooltip → `variant="compact"`

**Old:**

```tsx
{
  name: 'field',
  help: 'This is help text',
  showHelpInTooltip: true,
}
```

**New:**

```tsx
<field.Layout.Row
  label="Field"
  hintText="This is help text"
  variant="compact"
>
```

### disabledReason → `disabled="reason"`

**Old:**

```tsx
{
  name: 'field',
  disabled: true,
  disabledReason: 'Requires Business plan',
}
```

**New:**

```tsx
<field.Input
  disabled="Requires Business plan"
  {...}
/>
```

### extraHelp → JSX

**Old:**

```tsx
{
  name: 'sensitiveFields',
  help: 'Main help text',
  extraHelp: 'Note: These fields apply org-wide',
}
```

**New:**

```tsx
<field.Layout.Stack label="Sensitive Fields" hintText="Main help text">
  <field.TextArea {...} />
  <Text size="sm" variant="muted">
    Note: These fields apply org-wide
  </Text>
</field.Layout.Stack>
```

### getData → `mutationFn`

The `getData` function transformed field data before sending to the API. In the new system, handle this in the `mutationFn`.

**Old:**

```tsx
// Wrap field value in 'options' key
{
  name: 'sentry:csp_ignored_sources_defaults',
  type: 'boolean',
  getData: data => ({options: data}),
}

// Or extract/transform specific fields
{
  name: 'slug',
  getData: (data: {slug?: string}) => ({slug: data.slug}),
}
```

**New:**

```tsx
<AutoSaveForm
  name="sentry:csp_ignored_sources_defaults"
  schema={schema}
  initialValue={project.options['sentry:csp_ignored_sources_defaults']}
  mutationOptions={{
    mutationFn: data => {
      // Transform data before API call (equivalent to getData)
      const transformed = {options: data};
      return fetchMutation({
        url: `/projects/${organization.slug}/${project.slug}/`,
        method: 'PUT',
        data: transformed,
      });
    },
  }}
>
  {field => (
    <field.Layout.Row label="Use default ignored sources">
      <field.Switch checked={field.state.value} onChange={field.handleChange} />
    </field.Layout.Row>
  )}
</AutoSaveForm>
```

**Simpler pattern** - If you just need to wrap the value:

```tsx
mutationOptions={{
  mutationFn: fieldData => {
    return fetchMutation({
      url: `/projects/${org}/${project}/`,
      method: 'PUT',
      data: {options: fieldData}, // getData equivalent
    });
  },
}}
```

**Important: Typing mutations correctly**

The `mutationFn` should be typed with the API's data type (e.g., `Partial<Organization>`, `Partial<Project>`), **not** the schema-inferred type. The schema is for client-side field validation only — the mutation receives whatever the API endpoint accepts. Tying the mutation to the schema couples two unrelated concerns and can cause type errors when the schema types don't exactly match the API types.

```tsx
// ❌ Don't use generic types - breaks field type narrowing
mutationOptions={{
  mutationFn: (data: Record<string, unknown>) => {
    return fetchMutation({url: '/user/', method: 'PUT', data: {options: data}});
  },
}}

// ❌ Don't tie mutation type to the zod schema
mutationOptions={{
  mutationFn: (data: Partial<z.infer<typeof preferencesSchema>>) => {
    return fetchMutation({url: '/user/', method: 'PUT', data: {options: data}});
  },
}}

// ✅ Use the API's data type
mutationOptions={{
  mutationFn: (data: Partial<UserDetails>) => {
    return fetchMutation({url: '/user/', method: 'PUT', data: {options: data}});
  },
}}
```

Make sure the zod schema's types are compatible with (i.e., assignable to) the API type. For example, if the API expects a string unio
03

Trust audit

CAUTIONgrade B · trust 89/100 Install with care. The audit found things worth knowing before you trust its output.

LayerWhat it checksResult
L0Provenance & inventoryWARN
L1Static analysis of the codeNA
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
none-observed
Network
none-observed
Shell
none-observed
Dependencies
pinned
Secrets in source
none-found

Findings (2)

MEDIUMInventory / provenance · inv.symlink · CWE-1104
.claude/skills
.claude/skills
Why it matters. link not followed
MEDIUMInventory / provenance · inv.symlink · CWE-1104
api-docs/.node-version
api-docs/.node-version
Why it matters. link not followed

Gates applied: no_behavioural_pass.

Audited 2026-09-29 · audit v0.4.1 · source sha 42a3375c14f5full audit observations/trust-audit/skill/getsentry__migrate-frontend-forms.json · Report an issue / request a re-scan
04

Audit history

Every audit this skill has had.

DateSourceVerdictGradeScoreChange
2026-09-2942a3375c14f5CAUTIONB89first audit
05

Questions

What does the Migrate Frontend Forms skill do?

Developer-first error tracking and performance monitoring

Is Migrate Frontend Forms safe to install?

With care. The audit graded it B (89/100) and found 2 things worth knowing before you trust this skill, listed below with the exact line each was found on.

What can Migrate Frontend Forms access on my machine?

The audit observed no filesystem, network or shell use at all in its source.

How current is this page?

The grade is for one exact copy of the source (42a3375c14f5), read on 2026-09-29. The repository is watched, and a new audit runs when it changes — this is the first audit.

Advertisement