ref(performance): convert TransactionThresholdModal from class to function component#109574
Conversation
1148517 to
3518b34
Compare
| transactionThreshold, | ||
| transactionThresholdMetric, | ||
| }: Props) { | ||
| const [threshold, setThreshold] = useState<number | string | undefined>( |
There was a problem hiding this comment.
number | string | undefined
This seemed strange at first. But the threshold really is stored as sometimes a number (setThreshold(data.threshold);), sometimes a string (setThreshold(event.target.value);). Refactoring to parse the string / use event.target.valueAsNumber would be a bigger change.
3518b34 to
fb3127f
Compare
static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
Show resolved
Hide resolved
static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Dropped
projectprop causes wrong project in modal- Updated useEventViewProject to accept optional project parameter and check it first before falling back to eventView.project[0], ensuring the correct project is used in multi-project views.
- ✅ Fixed: DELETE request error handler completely removed in reset
- Added .catch() block to DELETE request chain in handleReset with proper error handling via addErrorMessage, preventing unhandled promise rejections.
Or push these changes by commenting:
@cursor push 61dfc50bc6
Preview (61dfc50bc6)
diff --git a/static/app/views/performance/transactionSummary/projectUtils.ts b/static/app/views/performance/transactionSummary/projectUtils.ts
--- a/static/app/views/performance/transactionSummary/projectUtils.ts
+++ b/static/app/views/performance/transactionSummary/projectUtils.ts
@@ -4,14 +4,22 @@
import {defined} from 'sentry/utils';
import type EventView from 'sentry/utils/discover/eventView';
-export function useEventViewProject(eventView: EventView, projects: Project[]) {
+export function useEventViewProject(
+ eventView: EventView,
+ projects: Project[],
+ project?: string
+) {
return useMemo(() => {
if (!defined(eventView)) {
return undefined;
}
+ if (defined(project)) {
+ return projects.find(proj => proj.id === project);
+ }
+
const projectId = String(eventView.project[0]);
return projects.find(proj => proj.id === projectId);
- }, [eventView, projects]);
+ }, [eventView, projects, project]);
}
diff --git a/static/app/views/performance/transactionSummary/transactionThresholdModal.tsx b/static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
--- a/static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
+++ b/static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
@@ -55,6 +55,7 @@
organization,
closeModal,
onApply,
+ project: projectProp,
projects,
transactionName,
transactionThreshold,
@@ -66,7 +67,7 @@
const [metric, setMetric] = useState<TransactionThresholdMetric | undefined>(
transactionThresholdMetric
);
- const project = useEventViewProject(eventView, projects);
+ const project = useEventViewProject(eventView, projects, projectProp);
const handleApply = (event: React.FormEvent) => {
event.preventDefault();
@@ -148,6 +149,14 @@
const errorMessage = err.responseJSON?.threshold ?? null;
addErrorMessage(errorMessage);
});
+ })
+ .catch(err => {
+ let errorMessage =
+ err.responseJSON?.threshold ?? err.responseJSON?.non_field_errors ?? null;
+ if (Array.isArray(errorMessage)) {
+ errorMessage = errorMessage[0];
+ }
+ addErrorMessage(errorMessage);
});
};
static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
Outdated
Show resolved
Hide resolved
static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
Show resolved
Hide resolved
fb3127f to
dcc0c47
Compare
dcc0c47 to
de8ad04
Compare
static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
Outdated
Show resolved
Hide resolved
de8ad04 to
ec5a4ae
Compare
ec5a4ae to
9e2ff7d
Compare
static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
Outdated
Show resolved
Hide resolved
static/app/views/performance/transactionSummary/transactionThresholdModal.tsx
Outdated
Show resolved
Hide resolved
50467c3 to
6cd8a2a
Compare
| .then(() => { | ||
| const projectThresholdUrl = `/projects/${organization.slug}/${project.slug}/transaction-threshold/configure/`; | ||
| this.props.api | ||
| return api |
There was a problem hiding this comment.
Note the intentional added return: this unifies the two .catch() clauses into one. this.state.error was previously unused. Now they both go into addErrorMessage.
6cd8a2a to
bb3efea
Compare

Extracts a shared
useEventViewProjectmemo hook from theTransactionThresholdButtoncomponent as created in #109567.Streamlines two things from the class component version:
this.state[field]setting withlodash/set; now it's directset*hook setter callsstate.errorwas never used for anything (errors are registered withaddErrorMessage); now it's removedStacked on #109567. I'll keep this as a draft for reference for now.✅Fixes EXP-809