Skip to content

Commit fe82c02

Browse files
authored
ref: migrate externalIssues to scrapsForm (#112094)
This PR migrates `externalIssues` - both the `ExternalIssueFor` and the `TicketRuleModal` over to the new form system with the `BackendJsonFormAdapter`. Note that the previous adapter version we had only supported auto-save fields because of settings, so this PR adds “normal” forms: - `BackendJsonAutoSaveForm` for auto-save - BackendJsonSubmitForm` for regular forms Rendering is “duplicated” on purpose, the fields, schemas and some utils are shared though. On type level, it’s quite hard to create an abstraction that can be shared between auto-save and submit, as auto-save creates one form per field.
1 parent 776213e commit fe82c02

19 files changed

+2124
-768
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,7 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get
832832
/static/app/components/core/ @getsentry/design-engineering
833833
/static/app/components/dnd/ @getsentry/design-engineering
834834
/static/app/components/pageFilters/ @getsentry/design-engineering
835+
/static/app/components/backendJsonFormAdapter/ @getsentry/design-engineering
835836
/static/app/icons/ @getsentry/design-engineering
836837
/static/app/stories/ @getsentry/design-engineering
837838
/static/app/components/commandPalette/ @getsentry/design-engineering

static/app/components/backendJsonFormAdapter/index.spec.tsx renamed to static/app/components/backendJsonFormAdapter/backendJsonAutoSaveForm.spec.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import {OrganizationFixture} from 'sentry-fixture/organization';
22

33
import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
44

5-
import {BackendJsonFormAdapter} from './';
5+
import {BackendJsonAutoSaveForm} from './backendJsonAutoSaveForm';
66

77
const org = OrganizationFixture();
88
const mutationOptions = {
99
mutationFn: jest.fn().mockResolvedValue({}),
1010
};
1111

12-
describe('BackendJsonFormAdapter', () => {
12+
describe('BackendJsonAutoSaveForm', () => {
1313
it('renders boolean field as Switch', () => {
1414
render(
15-
<BackendJsonFormAdapter
15+
<BackendJsonAutoSaveForm
1616
field={{
1717
name: 'sync_enabled',
1818
type: 'boolean',
@@ -31,7 +31,7 @@ describe('BackendJsonFormAdapter', () => {
3131

3232
it('renders text field as Input', () => {
3333
render(
34-
<BackendJsonFormAdapter
34+
<BackendJsonAutoSaveForm
3535
field={{
3636
name: 'webhook_url',
3737
type: 'string',
@@ -51,7 +51,7 @@ describe('BackendJsonFormAdapter', () => {
5151

5252
it('renders select field with options', () => {
5353
render(
54-
<BackendJsonFormAdapter
54+
<BackendJsonAutoSaveForm
5555
field={{
5656
name: 'priority',
5757
type: 'select',
@@ -75,7 +75,7 @@ describe('BackendJsonFormAdapter', () => {
7575

7676
it('renders table field with add button', () => {
7777
render(
78-
<BackendJsonFormAdapter
78+
<BackendJsonAutoSaveForm
7979
field={{
8080
name: 'table_field',
8181
type: 'table',
@@ -93,7 +93,7 @@ describe('BackendJsonFormAdapter', () => {
9393

9494
it('boolean toggle triggers POST', async () => {
9595
render(
96-
<BackendJsonFormAdapter
96+
<BackendJsonAutoSaveForm
9797
field={{
9898
name: 'sync_enabled',
9999
type: 'boolean',
@@ -118,7 +118,7 @@ describe('BackendJsonFormAdapter', () => {
118118

119119
it('handles disabled fields', () => {
120120
render(
121-
<BackendJsonFormAdapter
121+
<BackendJsonAutoSaveForm
122122
field={{
123123
name: 'sync_enabled',
124124
type: 'boolean',

static/app/components/backendJsonFormAdapter/index.tsx renamed to static/app/components/backendJsonFormAdapter/backendJsonAutoSaveForm.tsx

Lines changed: 5 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -11,71 +11,7 @@ import {ChoiceMapperDropdown, ChoiceMapperTable} from './choiceMapperAdapter';
1111
import {ProjectMapperAddRow, ProjectMapperTable} from './projectMapperAdapter';
1212
import {TableBody, TableHeaderRow} from './tableAdapter';
1313
import type {FieldValue, JsonFormAdapterFieldConfig} from './types';
14-
15-
function getZodType(fieldType: JsonFormAdapterFieldConfig['type']) {
16-
switch (fieldType) {
17-
case 'boolean':
18-
return z.boolean();
19-
case 'string':
20-
case 'text':
21-
case 'secret':
22-
case 'textarea':
23-
return z.string();
24-
case 'number':
25-
return z.number();
26-
case 'email':
27-
return z.email();
28-
case 'url':
29-
return z.url();
30-
case 'choice_mapper':
31-
return z.object({});
32-
case 'project_mapper':
33-
case 'table':
34-
return z.array(z.any());
35-
case 'select':
36-
case 'choice':
37-
return z.any();
38-
default:
39-
unreachable(fieldType);
40-
return z.any();
41-
}
42-
}
43-
44-
function transformChoices(
45-
choices?: Array<[value: string, label: string]>
46-
): Array<{label: string; value: string}> {
47-
if (!choices) {
48-
return [];
49-
}
50-
return choices.map(([value, label]) => ({value, label}));
51-
}
52-
53-
function getDefaultForType(fieldType: JsonFormAdapterFieldConfig['type']): unknown {
54-
switch (fieldType) {
55-
case 'boolean':
56-
return false;
57-
case 'string':
58-
case 'text':
59-
case 'url':
60-
case 'email':
61-
case 'secret':
62-
case 'textarea':
63-
return '';
64-
case 'number':
65-
return 0;
66-
case 'choice_mapper':
67-
return {};
68-
case 'project_mapper':
69-
case 'table':
70-
return [];
71-
case 'select':
72-
case 'choice':
73-
return null;
74-
default:
75-
unreachable(fieldType);
76-
return '';
77-
}
78-
}
14+
import {getDefaultForField, getZodType, transformChoices} from './utils';
7915

8016
interface BackendJsonFormAdapterProps<
8117
TField extends JsonFormAdapterFieldConfig,
@@ -87,7 +23,7 @@ interface BackendJsonFormAdapterProps<
8723
initialValue?: FieldValue<TField>;
8824
}
8925

90-
export function BackendJsonFormAdapter<
26+
export function BackendJsonAutoSaveForm<
9127
TField extends JsonFormAdapterFieldConfig,
9228
TData,
9329
TContext,
@@ -104,7 +40,7 @@ export function BackendJsonFormAdapter<
10440
[fieldName, field.type]
10541
);
10642

107-
const value = initialValue ?? field.default ?? getDefaultForType(field.type);
43+
const value = initialValue ?? field.default ?? getDefaultForField(field);
10844

10945
if (field.type === 'table') {
11046
return (
@@ -304,6 +240,8 @@ export function BackendJsonFormAdapter<
304240
/>
305241
</fieldApi.Layout.Row>
306242
);
243+
case 'blank':
244+
return null;
307245
default:
308246
unreachable(field);
309247
return null;

0 commit comments

Comments
 (0)