Skip to content

Conversation

@jasonyuezhang
Copy link
Owner

@jasonyuezhang jasonyuezhang commented Nov 20, 2025

Description

Currently we use a free form text field for the tagged event condition. We've had a few user issues that that the tagged event was configured on an event that hasn't been seen.

This is only using the tags seen on error events; this is a bit closer to the intent of the condition and hope this clarifies the condition for the user.


Copied from getsentry#103711
Original PR: getsentry#103711

Summary by CodeRabbit

  • New Features

    • Replaced manual tag entry with a dropdown selector that dynamically loads available organization tags, improving the tag selection experience.
  • Improvements

    • Added loading indicator while organization tags are being fetched, providing better user feedback during data loading.

✏️ Tip: You can customize this high-level summary in your review settings.

@propel-test-bot
Copy link

Replace free-text tag input with dropdown populated from organization tags

The PR converts the taggedEvent condition UI from a plain text input to a selectable dropdown. It fetches known tag keys for the current organization (limited to the Dataset.ERRORS dataset) and supplies them to a creatable AutomationBuilderSelect, allowing users to pick an existing tag or define a new one. A loading indicator is shown while tags are fetched, and the currently-selected value is preserved if it is not present in the fetched list.

Key Changes

• Replaced AutomationBuilderInput with AutomationBuilderSelect in static/app/views/automations/components/actionFilters/taggedEvent.tsx
• Introduced useFetchOrganizationTags call (with caching, Dataset.ERRORS, projectIds: ['-1']) to retrieve tag keys
• Added LoadingIndicator while data is loading and sorting logic for tag list
• Maintained backward compatibility by pre-pending unknown current tag to list

Affected Areas

static/app/views/automations/components/actionFilters/taggedEvent.tsx (UI for tag condition)

This summary was automatically generated by @propel-code-bot

@coderabbitai
Copy link

coderabbitai bot commented Nov 20, 2025

Walkthrough

The taggedEvent automation component has been refactored to replace a text input field with a creatable select dropdown that dynamically loads organization tags. The component now uses hooks to fetch tag data asynchronously, displays a loading indicator during data retrieval, and manages selection through structured option values.

Changes

Cohort / File(s) Change Summary
Tag Selection UI Refactor
static/app/views/automations/components/actionFilters/taggedEvent.tsx
Replaced input-based tag key field with creatable select dropdown. Added async tag loading via useFetchOrganizationTags hook, loading state indicator, sorted tag options, and updated onChange handler for SelectValue-based value management.

Sequence Diagram

sequenceDiagram
    participant Component as taggedEvent
    participant useOrg as useOrganization
    participant useFetch as useFetchOrganizationTags
    participant Select as Creatable Select
    participant Update as condition.key

    Component->>useOrg: Get organization
    Component->>useFetch: Fetch tags
    useFetch-->>Component: Loading...
    Note over Component: Show loading indicator
    useFetch-->>Component: Tag data loaded
    Component->>Component: Build options (sorted + current key)
    Component->>Select: Render with options
    Select->>Select: User selects tag
    Select->>Component: onChange(selectedValue)
    Component->>Update: Update condition.key
    Component->>Component: Clear errors
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Hook integration complexity: verify useOrganization and useFetchOrganizationTags usage patterns and error handling
  • Tag option derivation logic: confirm sorting and prepending of current condition key works correctly
  • Value transformation and onChange handler: ensure SelectValue mapping aligns with condition updates
  • Loading state management: verify loading indicator displays appropriately during data fetch

Poem

🐰 From text fields plain to dropdowns grand,
Tags now load from organization's land,
A creatable select with options bright,
Loading spinners dance while fetching right! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: replacing a free-form text field with a creatable select dropdown of organization tags for the tagged event condition.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch copy/pr-103711-jcallender/aci/tags-drop-down

Comment @coderabbitai help to get the list of available commands and usage tips.

@jason-test-bot
Copy link

try trigger propel code review

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
static/app/views/automations/components/actionFilters/taggedEvent.tsx (2)

58-64: Consider type consistency when prepending current key.

The logic correctly preserves existing selections, but line 63 mixes object types—tags contains tag objects from the API, while condition.comparison is a comparison object with {key, match, value}. Although both have a .key property (which is all that's needed for mapping at lines 73-76), this creates semantic inconsistency.

For better type safety, consider normalizing to a consistent shape:

  if (
    condition.comparison.key &&
    !tags.some(tag => tag.key === condition.comparison.key)
  ) {
-   tags.unshift(condition.comparison);
+   tags.unshift({key: condition.comparison.key});
  }

48-48: Optional: Remove redundant parameter.

The enabled: true parameter is typically the default for data-fetching hooks and can be omitted for cleaner code.

      dataset: Dataset.ERRORS,
      useCache: true,
-     enabled: true,
      keepPreviousData: true,
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52b4a88 and 982296f.

📒 Files selected for processing (1)
  • static/app/views/automations/components/actionFilters/taggedEvent.tsx (2 hunks)
🔇 Additional comments (2)
static/app/views/automations/components/actionFilters/taggedEvent.tsx (2)

1-9: LGTM! Imports align with PR objectives.

The new imports support the tag fetching functionality and correctly scope to error events using Dataset.ERRORS, which aligns with the PR goal of showing tags from error events only.


40-56: The review comment's concerns are not valid. The code is correct as written.

  1. projectIds: ['-1'] is the correct API syntax. Evidence shows discover/results.tsx:284 explicitly compares currentQuery.project[0] === '-1' (string format), confirming the API accepts string '-1' as the sentinel value for querying all projects.

  2. LoadingIndicator in tct() renders correctly. The tct() function is designed to interpolate React components into translated strings. Returning <LoadingIndicator /> from KeyField during the loading state is the standard pattern and will display properly without breaking the layout.

Likely an incorrect or invalid review comment.

Comment on lines +77 to +78
onChange={(e: SelectValue<MatchType>) => {
onUpdate({comparison: {...condition.comparison, key: e.value}});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix incorrect type annotation.

The onChange handler is annotated as SelectValue<MatchType>, but MatchType is for the match field (line 93), not the key field. The key is a string representing a tag name.

Apply this diff to fix the type:

-     onChange={(e: SelectValue<MatchType>) => {
+     onChange={(e: SelectValue<string>) => {
        onUpdate({comparison: {...condition.comparison, key: e.value}});
        removeError(condition.id);
      }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onChange={(e: SelectValue<MatchType>) => {
onUpdate({comparison: {...condition.comparison, key: e.value}});
onChange={(e: SelectValue<string>) => {
onUpdate({comparison: {...condition.comparison, key: e.value}});
🤖 Prompt for AI Agents
In static/app/views/automations/components/actionFilters/taggedEvent.tsx around
lines 77-78, the onChange handler is incorrectly typed as SelectValue<MatchType>
even though it updates the key (a string tag name); change the handler's
parameter type to SelectValue<string> (or the appropriate string alias) and keep
using e.value when calling onUpdate so the comparison.key is correctly typed as
a string.

Comment on lines +77 to 80
onChange={(e: SelectValue<MatchType>) => {
onUpdate({comparison: {...condition.comparison, key: e.value}});
removeError(condition.id);
}}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[DataTypeCheck]

Type safety issue: The onChange handler expects SelectValue<MatchType>, but the actual data is tag keys (strings), not MatchType. This type mismatch could cause runtime issues or type errors.

Fix: Use the correct generic type:

Suggested change
onChange={(e: SelectValue<MatchType>) => {
onUpdate({comparison: {...condition.comparison, key: e.value}});
removeError(condition.id);
}}
onChange={(e: SelectValue<string>) => {
onUpdate({comparison: {...condition.comparison, key: e.value}});
removeError(condition.id);
}}

Committable suggestion

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Context for Agents
**Type safety issue**: The `onChange` handler expects `SelectValue<MatchType>`, but the actual data is tag keys (strings), not `MatchType`. This type mismatch could cause runtime issues or type errors.

**Fix**: Use the correct generic type:
```suggestion
      onChange={(e: SelectValue<string>) => {
        onUpdate({comparison: {...condition.comparison, key: e.value}});
        removeError(condition.id);
      }}
```

⚡ **Committable suggestion**

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

File: static/app/views/automations/components/actionFilters/taggedEvent.tsx
Line: 80

return <LoadingIndicator mini size={24} style={{alignItems: 'center'}} />;
}

const tags = tagOptions.sort((a, b) => a.key.localeCompare(b.key));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[BestPractice]

Array mutation issue: The sort() method mutates the original tagOptions array in-place. If this array is shared (e.g., from a cached query result), this could cause unexpected side effects or affect other components.

Fix: Create a shallow copy before sorting:

Suggested change
const tags = tagOptions.sort((a, b) => a.key.localeCompare(b.key));
const tags = [...tagOptions].sort((a, b) => a.key.localeCompare(b.key));

Committable suggestion

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Context for Agents
**Array mutation issue**: The `sort()` method mutates the original `tagOptions` array in-place. If this array is shared (e.g., from a cached query result), this could cause unexpected side effects or affect other components.

**Fix**: Create a shallow copy before sorting:
```suggestion
  const tags = [...tagOptions].sort((a, b) => a.key.localeCompare(b.key));
```

⚡ **Committable suggestion**

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

File: static/app/views/automations/components/actionFilters/taggedEvent.tsx
Line: 58

Comment on lines +42 to +56
const {data: tagOptions, isLoading} = useFetchOrganizationTags(
{
orgSlug: organization.slug,
projectIds: ['-1'],
dataset: Dataset.ERRORS,
useCache: true,
enabled: true,
keepPreviousData: true,
},
{}
);

if (!tagOptions || isLoading) {
return <LoadingIndicator mini size={24} style={{alignItems: 'center'}} />;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[BestPractice]

Missing error handling: When useFetchOrganizationTags fails (network error, API failure, etc.), the component only shows a loading indicator indefinitely. Users have no feedback that something went wrong or how to recover.

Consider adding error state handling:

  • Check for error state from the hook (e.g., const {data: tagOptions, isLoading, error} = useFetchOrganizationTags(...))
  • Display an error message or fallback UI when fetch fails
  • Potentially fall back to a plain text input if tags cannot be loaded
Context for Agents
**Missing error handling**: When `useFetchOrganizationTags` fails (network error, API failure, etc.), the component only shows a loading indicator indefinitely. Users have no feedback that something went wrong or how to recover.

**Consider adding error state handling**:
- Check for error state from the hook (e.g., `const {data: tagOptions, isLoading, error} = useFetchOrganizationTags(...)`)
- Display an error message or fallback UI when fetch fails
- Potentially fall back to a plain text input if tags cannot be loaded

File: static/app/views/automations/components/actionFilters/taggedEvent.tsx
Line: 56

Comment on lines +73 to +76
options={Object.values(tags).map(tag => ({
value: tag.key,
label: tag.key,
}))}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[BestPractice]

Unnecessary Object.values() call: The tags variable is already an array (from sort()), so wrapping it in Object.values() is redundant and could cause confusion.

Fix: Remove the unnecessary wrapper:

Suggested change
options={Object.values(tags).map(tag => ({
value: tag.key,
label: tag.key,
}))}
options={tags.map(tag => ({
value: tag.key,
label: tag.key,
}))}

Committable suggestion

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Context for Agents
**Unnecessary `Object.values()` call**: The `tags` variable is already an array (from `sort()`), so wrapping it in `Object.values()` is redundant and could cause confusion.

**Fix**: Remove the unnecessary wrapper:
```suggestion
      options={tags.map(tag => ({
        value: tag.key,
        label: tag.key,
      }))}
```

⚡ **Committable suggestion**

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

File: static/app/views/automations/components/actionFilters/taggedEvent.tsx
Line: 76

@jason-test-bot
Copy link

try trigger propel code review again

@jason-test-bot
Copy link

try trigger propel code review~

@jason-test-bot
Copy link

try trigger propel code review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants