Skip to content

Commit cd5438b

Browse files
ref(forms): Make mapFormErrors a form model option (#47120)
This allows specialization of form error response mapping without needing to extend the FormModel class
1 parent c041e00 commit cd5438b

File tree

2 files changed

+37
-33
lines changed

2 files changed

+37
-33
lines changed

static/app/components/forms/model.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ export type FormOptions = {
3434
* Initial form data
3535
*/
3636
initialData?: Record<string, FieldValue>;
37+
/**
38+
* Custom transformer function for use with the error response
39+
*/
40+
mapFormErrors?: (responseJson: any) => any;
3741
/**
3842
* Callback triggered when a field changes value
3943
*/
@@ -746,12 +750,12 @@ class FormModel {
746750

747751
submitError(err: {responseJSON?: any}) {
748752
this.formState = FormState.ERROR;
749-
this.formErrors = this.mapFormErrors(err.responseJSON);
750-
this.handleErrorResponse({responseJSON: this.formErrors});
751-
}
752753

753-
mapFormErrors(responseJSON?: any) {
754-
return responseJSON;
754+
this.formErrors = this.options.mapFormErrors
755+
? this.options.mapFormErrors(err.responseJSON)
756+
: err.responseJSON;
757+
758+
this.handleErrorResponse({responseJSON: this.formErrors});
755759
}
756760
}
757761

static/app/views/settings/organizationDeveloperSettings/sentryApplicationDetails.tsx

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,33 @@ const getResourceFromScope = (scope: Scope): Resource | undefined => {
8484
return undefined;
8585
};
8686

87+
/**
88+
* We need to map the API response errors to the actual form fields.
89+
* We do this by pulling out scopes and mapping each scope error to the correct input.
90+
* @param {Object} responseJSON
91+
*/
92+
const mapFormErrors = (responseJSON?: any) => {
93+
if (!responseJSON) {
94+
return responseJSON;
95+
}
96+
const formErrors = omit(responseJSON, ['scopes']);
97+
if (responseJSON.scopes) {
98+
responseJSON.scopes.forEach((message: string) => {
99+
// find the scope from the error message of a specific format
100+
const matches = message.match(/Requested permission of (\w+:\w+)/);
101+
if (matches) {
102+
const scope = matches[1];
103+
const resource = getResourceFromScope(scope as Scope);
104+
// should always match but technically resource can be undefined
105+
if (resource) {
106+
formErrors[`${resource}--permission`] = [message];
107+
}
108+
}
109+
});
110+
}
111+
return formErrors;
112+
};
113+
87114
class SentryAppFormModel extends FormModel {
88115
/**
89116
* Filter out Permission input field values.
@@ -106,33 +133,6 @@ class SentryAppFormModel extends FormModel {
106133
return data;
107134
}, {});
108135
}
109-
110-
/**
111-
* We need to map the API response errors to the actual form fields.
112-
* We do this by pulling out scopes and mapping each scope error to the correct input.
113-
* @param {Object} responseJSON
114-
*/
115-
mapFormErrors(responseJSON?: any) {
116-
if (!responseJSON) {
117-
return responseJSON;
118-
}
119-
const formErrors = omit(responseJSON, ['scopes']);
120-
if (responseJSON.scopes) {
121-
responseJSON.scopes.forEach((message: string) => {
122-
// find the scope from the error message of a specific format
123-
const matches = message.match(/Requested permission of (\w+:\w+)/);
124-
if (matches) {
125-
const scope = matches[1];
126-
const resource = getResourceFromScope(scope as Scope);
127-
// should always match but technically resource can be undefined
128-
if (resource) {
129-
formErrors[`${resource}--permission`] = [message];
130-
}
131-
}
132-
});
133-
}
134-
return formErrors;
135-
}
136136
}
137137

138138
type Props = RouteComponentProps<{appSlug?: string}, {}> & {
@@ -145,7 +145,7 @@ type State = AsyncView['state'] & {
145145
};
146146

147147
class SentryApplicationDetails extends AsyncView<Props, State> {
148-
form = new SentryAppFormModel();
148+
form = new SentryAppFormModel({mapFormErrors});
149149

150150
getDefaultState(): State {
151151
return {

0 commit comments

Comments
 (0)