Skip to content

Commit 1c761a8

Browse files
committed
Merge remote-tracking branch 'origin/master' into feat/unity-metrics
# Conflicts: # static/app/data/platformCategories.tsx
2 parents d9934e2 + 939e726 commit 1c761a8

1,533 files changed

Lines changed: 47460 additions & 20907 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/cell-architecture/SKILL.md

Lines changed: 267 additions & 0 deletions
Large diffs are not rendered by default.

.agents/skills/design-system/SKILL.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import {Container} from '@sentry/scraps/layout';
5151

5252
// ❌ Don't create styled components
5353
const Component = styled('div')`
54-
padding: ${space(2)};
54+
padding: ${p => p.theme.space.md};
5555
border: 1px solid ${p => p.theme.tokens.border.primary};
5656
`;
5757

@@ -119,7 +119,7 @@ import {Grid} from '@sentry/scraps/layout';
119119
const Component = styled('div')`
120120
display: grid;
121121
grid-template-columns: repeat(3, 1fr);
122-
gap: ${space(2)};
122+
gap: ${p => p.theme.space.md};
123123
`;
124124

125125
// ✅ Use Grid primitive
@@ -147,7 +147,7 @@ import {Stack} from '@sentry/scraps/layout';
147147
const Component = styled('div')`
148148
display: flex;
149149
flex-direction: column;
150-
gap: ${space(2)};
150+
gap: ${p => p.theme.space.md};
151151
`;
152152

153153
// ✅ Use Stack primitive (automatically column direction)
@@ -204,7 +204,7 @@ import {Text} from '@sentry/scraps/text';
204204
// ❌ Don't create styled text components
205205
const Label = styled('span')`
206206
color: ${p => p.theme.tokens.content.secondary};
207-
font-size: ${p => p.theme.fontSizes.small};
207+
font-size: ${p => p.theme.font.size.sm};
208208
`;
209209

210210
// ❌ Don't use raw elements
@@ -242,7 +242,7 @@ import {Heading} from '@sentry/scraps/text';
242242

243243
// ❌ Don't style heading elements
244244
const Title = styled('h2')`
245-
font-size: ${p => p.theme.fontSize.md};
245+
font-size: ${p => p.theme.font.size.md};
246246
font-weight: bold;
247247
`;
248248

@@ -401,7 +401,7 @@ Container supports `margin` props but they are deprecated. Use `gap` on parent c
401401
```tsx
402402
// ❌ Don't use margin between children
403403
const Child = styled('div')`
404-
margin-right: ${p => p.theme.spacing.lg};
404+
margin-right: ${p => p.theme.space.lg};
405405
`;
406406

407407
// ✅ Use gap on parent container
@@ -421,7 +421,7 @@ const Component = styled('div')`
421421
display: flex;
422422
flex-direction: column;
423423
color: ${p => p.theme.tokens.content.secondary};
424-
font-size: ${p => p.theme.fontSize.lg};
424+
font-size: ${p => p.theme.font.size.lg};
425425
`;
426426

427427
// ✅ Split into layout and typography primitives

.agents/skills/generate-frontend-forms/SKILL.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,20 @@ function MyForm() {
732732
}
733733
```
734734

735+
### Resetting After Save
736+
737+
When a form stays on the page after submission (e.g., settings pages), call `form.reset()` after a successful mutation. This re-syncs the form with updated `defaultValues` so it becomes pristine again — any UI that depends on the form being dirty (like conditionally shown Save/Cancel buttons) will update correctly.
738+
739+
```tsx
740+
onSubmit: ({value}) =>
741+
mutation
742+
.mutateAsync(value)
743+
.then(() => form.reset())
744+
.catch(() => {}),
745+
```
746+
747+
> **Note**: `AutoSaveForm` handles this automatically. You only need to add this when using `useScrapsForm`.
748+
735749
### Submit Button
736750

737751
```tsx
@@ -828,7 +842,11 @@ onSubmit: ({value}) => {
828842
// Return the promise to keep form.isSubmitting working
829843
// Add .catch(() => {}) to avoid unhandled rejection - error handling
830844
// is done by TanStack Query (onError callback, mutation.isError state)
831-
return mutation.mutateAsync(value).catch(() => {});
845+
// Add .then(() => form.reset()) if the form stays on the page after save
846+
return mutation
847+
.mutateAsync(value)
848+
.then(() => form.reset())
849+
.catch(() => {});
832850
};
833851
```
834852

@@ -915,6 +933,23 @@ const opts = mutationOptions({
915933

916934
Make sure the zod schema's types are compatible with the API type. For example, if the API expects a string union like `'off' | 'low' | 'high'`, use `z.enum(['off', 'low', 'high'])` instead of `z.string()`.
917935

936+
### Form Reset After Save
937+
938+
```tsx
939+
// ❌ Don't forget to reset forms that stay on the page after save
940+
onSubmit: ({value}) => {
941+
return mutation.mutateAsync(value).catch(() => {});
942+
};
943+
944+
// ✅ Call form.reset() after successful save to sync with updated defaultValues
945+
onSubmit: ({value}) => {
946+
return mutation
947+
.mutateAsync(value)
948+
.then(() => form.reset())
949+
.catch(() => {});
950+
};
951+
```
952+
918953
### Layout Choice
919954

920955
```tsx
@@ -941,6 +976,7 @@ When creating a new form:
941976
- [ ] Choose appropriate layout (Stack or Row)
942977
- [ ] Handle server errors with `setFieldErrors`
943978
- [ ] Add `<form.SubmitButton>` for submission
979+
- [ ] Call `form.reset()` after successful mutation if the form stays on the page
944980

945981
When creating auto-save fields:
946982

.agents/skills/migrate-frontend-forms/SKILL.md

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,23 @@ This skill helps migrate forms from Sentry's legacy form system (JsonForm, FormM
99

1010
## Feature Mapping
1111

12-
| Old System | New System | Notes |
13-
| -------------------- | ------------------- | -------------------------------------------- |
14-
| `saveOnBlur: true` | `AutoSaveForm` | Default behavior |
15-
| `confirm` | `confirm` prop | `string \| ((value) => string \| undefined)` |
16-
| `showHelpInTooltip` | `variant="compact"` | On layout components |
17-
| `disabledReason` | `disabled="reason"` | String shows tooltip |
18-
| `extraHelp` | JSX in layout | Render `<Text>` below field |
19-
| `getData` | `mutationFn` | Transform data in mutation function |
20-
| `mapFormErrors` | `setFieldErrors` | Transform API errors in catch block |
21-
| `saveMessage` | `onSuccess` | Show toast in mutation onSuccess callback |
22-
| `formatMessageValue` | `onSuccess` | Control toast content in onSuccess callback |
23-
| `resetOnError` | `onError` | Call form.reset() in mutation onError |
24-
| `saveOnBlur: false` | `useScrapsForm` | Use regular form with explicit Save button |
25-
| `help` | `hintText` | On layout components |
26-
| `label` | `label` | On layout components |
27-
| `required` | `required` | On layout + Zod schema |
12+
| Old System | New System | Notes |
13+
| -------------------- | ------------------- | ---------------------------------------------------- |
14+
| `saveOnBlur: true` | `AutoSaveForm` | Default behavior |
15+
| `confirm` | `confirm` prop | `string \| ((value) => string \| undefined)` |
16+
| `showHelpInTooltip` | `variant="compact"` | On layout components |
17+
| `disabledReason` | `disabled="reason"` | String shows tooltip |
18+
| `extraHelp` | JSX in layout | Render `<Text>` below field |
19+
| `getData` | `mutationFn` | Transform data in mutation function |
20+
| `mapFormErrors` | `setFieldErrors` | Transform API errors in catch block |
21+
| `saveMessage` | `onSuccess` | Show toast in mutation onSuccess callback |
22+
| `formatMessageValue` | `onSuccess` | Control toast content in onSuccess callback |
23+
| `resetOnError` | `onError` | Call form.reset() in mutation onError |
24+
| `saveOnBlur: false` | `useScrapsForm` | Use regular form with explicit Save button |
25+
| (automatic) | `form.reset()` | Call after successful mutation if form stays on page |
26+
| `help` | `hintText` | On layout components |
27+
| `label` | `label` | On layout components |
28+
| `required` | `required` | On layout + Zod schema |
2829

2930
## Feature Details
3031

@@ -410,6 +411,20 @@ const form = useScrapsForm({
410411

411412
> **Note**: AutoSaveForm with TanStack Query already handles error states gracefully - the mutation's `isError` state is reflected in the UI. Manual reset is typically only needed for specific UX requirements like password fields.
412413

414+
### Resetting After Save
415+
416+
When using `useScrapsForm` for a form that stays on the page after save, call `form.reset()` after a successful mutation. This re-syncs the form with updated `defaultValues` so it becomes pristine again — any UI that depends on the form being dirty (like conditionally shown Save/Cancel buttons) will update correctly.
417+
418+
```tsx
419+
onSubmit: ({value}) =>
420+
mutation
421+
.mutateAsync(value)
422+
.then(() => form.reset())
423+
.catch(() => {}),
424+
```
425+
426+
> **Note**: `AutoSaveForm` handles this automatically. You only need to add this when using `useScrapsForm`.
427+
413428
### saveOnBlur: false → `useScrapsForm`
414429

415430
Fields with `saveOnBlur: false` showed an inline alert with Save/Cancel buttons instead of auto-saving. This was used for dangerous operations (slug changes) or large text edits (fingerprint rules).
@@ -597,6 +612,7 @@ This pattern is necessary whenever a required field has no meaningful initial va
597612
- [ ] Handle `mapFormErrors` with setFieldErrors in catch
598613
- [ ] Handle `saveMessage` in onSuccess callback
599614
- [ ] Convert `saveOnBlur: false` fields to regular forms with Save button
615+
- [ ] Call `form.reset()` after successful mutation (for forms that stay on page)
600616
- [ ] Verify `onSuccess` cache updates merge with existing data (use updater function) — some API endpoints may return partial objects
601617
- [ ] Wrap the migrated form with `<FormSearch route="...">` if the old form was searchable in SettingsSearch
602618
- [ ] Run `pnpm run extract-form-fields` and commit the updated `generatedFieldRegistry.ts`

0 commit comments

Comments
 (0)