Skip to content

Commit 4627b7b

Browse files
committed
fix(issues): Escape status tag on search
Tag keys that conflict with our issue keys must be escaped fixes #89369
1 parent c532636 commit 4627b7b

File tree

5 files changed

+57
-5
lines changed

5 files changed

+57
-5
lines changed

static/app/components/events/eventTags/eventTagsTreeRow.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {t} from 'sentry/locale';
1717
import {space} from 'sentry/styles/space';
1818
import type {Event} from 'sentry/types/event';
1919
import type {Project} from 'sentry/types/project';
20-
import {generateQueryWithTag} from 'sentry/utils';
20+
import {escapeIssueTagKey, generateQueryWithTag} from 'sentry/utils';
2121
import {isEmptyObject} from 'sentry/utils/object/isEmptyObject';
2222
import {isUrl} from 'sentry/utils/string/isUrl';
2323
import useCopyToClipboard from 'sentry/utils/useCopyToClipboard';
@@ -150,7 +150,14 @@ function EventTagsTreeRowDropdown({
150150
project?.highlightTags &&
151151
// Skip tags already highlighted
152152
highlightTagSet.has(originalTag.key);
153-
const query = generateQueryWithTag({referrer}, originalTag);
153+
const query = generateQueryWithTag(
154+
{referrer},
155+
{
156+
...originalTag,
157+
key: escapeIssueTagKey(originalTag.key),
158+
}
159+
);
160+
154161
const isProjectAdmin = hasEveryAccess(['project:admin'], {
155162
organization,
156163
project,

static/app/utils.spec.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {escapeIssueTagKey} from './utils';
2+
3+
describe('escapeIssueTagKey', () => {
4+
it('should escape conflicting tag keys', () => {
5+
expect(escapeIssueTagKey('status')).toBe('tags[status]');
6+
expect(escapeIssueTagKey('message')).toBe('tags[message]');
7+
});
8+
9+
it('should not escape environment and project', () => {
10+
expect(escapeIssueTagKey('environment')).toBe('environment');
11+
expect(escapeIssueTagKey('project')).toBe('project');
12+
});
13+
});

static/app/utils.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import type {Query} from 'history';
22

33
import type {EventTag} from 'sentry/types/event';
4+
import {
5+
type FieldKey,
6+
ISSUE_EVENT_FIELDS_THAT_MAY_CONFLICT_WITH_TAGS,
7+
} from 'sentry/utils/fields';
48
import {appendTagCondition} from 'sentry/utils/queryString';
59

610
export function intcomma(x: number): string {
@@ -92,6 +96,22 @@ export function isWebpackChunkLoadingError(error: Error): boolean {
9296
);
9397
}
9498

99+
/**
100+
* If a tag conflicts with a reserved keyword, change it to `tags[key]:value`
101+
*/
102+
export function escapeIssueTagKey(key: string) {
103+
// Environment and project should be handled by the page filter
104+
if (key === 'environment' || key === 'project') {
105+
return key;
106+
}
107+
108+
if (ISSUE_EVENT_FIELDS_THAT_MAY_CONFLICT_WITH_TAGS.has(key as FieldKey)) {
109+
return `tags[${key}]`;
110+
}
111+
112+
return key;
113+
}
114+
95115
export function generateQueryWithTag(prevQuery: Query, tag: EventTag): Query {
96116
const query = {...prevQuery};
97117

static/app/utils/fields/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export enum FieldKey {
106106
STACK_PACKAGE = 'stack.package',
107107
STACK_RESOURCE = 'stack.resource',
108108
STACK_STACK_LEVEL = 'stack.stack_level',
109+
STATUS = 'status',
109110
TIMESTAMP = 'timestamp',
110111
TIMESTAMP_TO_DAY = 'timestamp.to_day',
111112
TIMESTAMP_TO_HOUR = 'timestamp.to_hour',
@@ -1703,6 +1704,11 @@ const EVENT_FIELD_DEFINITIONS: Record<AllEventFieldKeys, FieldDefinition> = {
17031704
kind: FieldKind.FIELD,
17041705
valueType: FieldValueType.NUMBER,
17051706
},
1707+
[FieldKey.STATUS]: {
1708+
desc: t('Status of the issue'),
1709+
kind: FieldKind.FIELD,
1710+
valueType: FieldValueType.STRING,
1711+
},
17061712
[FieldKey.TIMES_SEEN]: {
17071713
desc: t('Total number of events'),
17081714
kind: FieldKind.FIELD,
@@ -1993,6 +1999,7 @@ export const ISSUE_EVENT_FIELDS_THAT_MAY_CONFLICT_WITH_TAGS: Set<FieldKey> = new
19931999
FieldKey.STACK_MODULE,
19942000
FieldKey.STACK_PACKAGE,
19952001
FieldKey.STACK_STACK_LEVEL,
2002+
FieldKey.STATUS,
19962003
FieldKey.TIMESTAMP,
19972004
FieldKey.TITLE,
19982005
FieldKey.TRACE,

static/app/views/issueDetails/groupTags/tagDetailsDrawerContent.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {IconArrow, IconEllipsis, IconOpen} from 'sentry/icons';
1818
import {t, tct} from 'sentry/locale';
1919
import {space} from 'sentry/styles/space';
2020
import type {Group, Tag, TagValue} from 'sentry/types/group';
21-
import {percent} from 'sentry/utils';
21+
import {escapeIssueTagKey, generateQueryWithTag, percent} from 'sentry/utils';
2222
import {SavedQueryDatasets} from 'sentry/utils/discover/types';
2323
import {isUrl} from 'sentry/utils/string/isUrl';
2424
import useCopyToClipboard from 'sentry/utils/useCopyToClipboard';
@@ -251,8 +251,13 @@ function TagValueActionsMenu({
251251
const {onClick: handleCopy} = useCopyToClipboard({
252252
text: tagValue.value,
253253
});
254-
const key = tagValue.key ?? tag.key;
255-
const query = {query: tagValue.query || `${key}:"${tagValue.value}"`};
254+
const referrer = 'tag-details-drawer';
255+
const key = escapeIssueTagKey(tagValue.key ?? tag.key);
256+
const query = tagValue.query
257+
? {
258+
query: tagValue.query,
259+
}
260+
: generateQueryWithTag({referrer}, {key, value: tagValue.value});
256261
const eventView = useIssueDetailsEventView({group, queryProps: query});
257262
const [isVisible, setIsVisible] = useState(false);
258263

0 commit comments

Comments
 (0)