Skip to content

Commit e8b6e11

Browse files
committed
Merge branch 'master' into scttcper/typescript-4-fixes
2 parents 03f1cb6 + 8a82aff commit e8b6e11

File tree

17 files changed

+433
-100
lines changed

17 files changed

+433
-100
lines changed

src/sentry/api/serializers/models/integration.py

+4
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,16 @@ def serialize(self, obj, attrs, user):
6969
except NotImplementedError:
7070
# slack doesn't have an installation implementation
7171
config_data = obj.config
72+
dynamic_display_information = None
7273
else:
7374
# just doing this to avoid querying for an object we already have
7475
installation._org_integration = obj
7576
config_data = installation.get_config_data()
77+
dynamic_display_information = installation.get_dynamic_display_information()
7678

7779
integration.update({"configData": config_data})
80+
if dynamic_display_information:
81+
integration.update({"dynamicDisplayInformation": dynamic_display_information})
7882

7983
return integration
8084

src/sentry/api/serializers/models/release.py

+3
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,14 @@ def get_attrs(self, item_list, user, **kwargs):
263263
first_seen, last_seen, issue_counts_by_release = self.__get_release_data_no_environment(
264264
project, item_list
265265
)
266+
environments = None
266267
else:
267268
(
268269
first_seen,
269270
last_seen,
270271
issue_counts_by_release,
271272
) = self.__get_release_data_with_environment(project, item_list, environment)
273+
environments = [environment]
272274

273275
owners = {
274276
d["id"]: d for d in serialize(set(i.owner for i in item_list if i.owner_id), user)
@@ -300,6 +302,7 @@ def get_attrs(self, item_list, user, **kwargs):
300302
[(pr["project__id"], pr["release__version"]) for pr in project_releases],
301303
health_stats_period=health_stats_period,
302304
summary_stats_period=summary_stats_period,
305+
environments=environments,
303306
stat=health_stat,
304307
)
305308
else:

src/sentry/eventstream/base.py

+27-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
from __future__ import absolute_import
22

3+
import random
34
import logging
45

5-
from sentry.utils.services import Service
6+
from sentry import options
67
from sentry.tasks.post_process import post_process_group
8+
from sentry.utils.services import Service
9+
from sentry.utils.cache import cache_key_for_event
710

811

912
logger = logging.getLogger(__name__)
@@ -43,13 +46,30 @@ def _dispatch_post_process_group_task(
4346
if skip_consume:
4447
logger.info("post_process.skip.raw_event", extra={"event_id": event.event_id})
4548
else:
46-
post_process_group.delay(
47-
event=event,
48-
is_new=is_new,
49-
is_regression=is_regression,
50-
is_new_group_environment=is_new_group_environment,
51-
primary_hash=primary_hash,
49+
random_val = random.random()
50+
cache_key = cache_key_for_event(
51+
{"project": event.project_id, "event_id": event.event_id}
5252
)
53+
if options.get("postprocess.use-cache-key") > random_val:
54+
post_process_group.delay(
55+
event=None,
56+
is_new=is_new,
57+
is_regression=is_regression,
58+
is_new_group_environment=is_new_group_environment,
59+
primary_hash=primary_hash,
60+
cache_key=cache_key,
61+
group_id=event.group_id,
62+
)
63+
else:
64+
# Pass the cache key here to ensure that the processing cache is removed.
65+
post_process_group.delay(
66+
event=event,
67+
is_new=is_new,
68+
is_regression=is_regression,
69+
is_new_group_environment=is_new_group_environment,
70+
primary_hash=primary_hash,
71+
cache_key=cache_key,
72+
)
5373

5474
def insert(
5575
self,

src/sentry/integrations/base.py

+3
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,9 @@ def update_organization_config(self, data):
289289
def get_config_data(self):
290290
return self.org_integration.config
291291

292+
def get_dynamic_display_information(self):
293+
return None
294+
292295
def get_client(self):
293296
# Return the api client for a given provider
294297
raise NotImplementedError

src/sentry/integrations/slack/tasks.py

+3-22
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,7 @@ def _format_value(self, status, rule_id):
5858

5959

6060
@instrumented_task(name="sentry.integrations.slack.search_channel_id", queue="integrations")
61-
def find_channel_id_for_rule(
62-
name,
63-
environment,
64-
project,
65-
action_match,
66-
filter_match,
67-
conditions,
68-
actions,
69-
frequency,
70-
uuid,
71-
rule_id=None,
72-
):
61+
def find_channel_id_for_rule(project, actions, uuid, rule_id=None, **kwargs):
7362
redis_rule_status = RedisRuleStatus(uuid)
7463

7564
try:
@@ -118,16 +107,8 @@ def find_channel_id_for_rule(
118107
action["channel_id"] = item_id
119108
break
120109

121-
kwargs = {
122-
"name": name,
123-
"environment": environment,
124-
"project": project,
125-
"action_match": action_match,
126-
"filter_match": filter_match,
127-
"conditions": conditions,
128-
"actions": actions,
129-
"frequency": frequency,
130-
}
110+
kwargs["actions"] = actions
111+
kwargs["project"] = project
131112

132113
if rule_id:
133114
rule = Rule.objects.get(id=rule_id)

src/sentry/integrations/vercel/integration.py

+32-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from django.utils.translation import ugettext_lazy as _
88
from rest_framework.serializers import ValidationError
9+
from six.moves.urllib.parse import urlencode
910

1011

1112
from sentry.integrations import (
@@ -21,6 +22,7 @@
2122
from sentry.identity.pipeline import IdentityProviderPipeline
2223
from sentry.utils.http import absolute_uri
2324
from sentry.models import (
25+
Organization,
2426
Integration,
2527
Project,
2628
ProjectKey,
@@ -36,9 +38,11 @@
3638

3739
logger = logging.getLogger("sentry.integrations.vercel")
3840

39-
DESCRIPTION = """
41+
DESCRIPTION = _(
42+
"""
4043
Vercel is an all-in-one platform with Global CDN supporting static & JAMstack deployment and Serverless Functions.
4144
"""
45+
)
4246

4347
FEATURES = [
4448
FeatureDescription(
@@ -49,7 +53,7 @@
4953
),
5054
]
5155

52-
INSTALL_NOTICE_TEXT = (
56+
INSTALL_NOTICE_TEXT = _(
5357
"Visit the Vercel Marketplace to install this integration. After installing the"
5458
" Sentry integration, you'll be redirected back to Sentry to finish syncing Vercel and Sentry projects."
5559
)
@@ -63,11 +67,19 @@
6367

6468

6569
configure_integration = {"title": _("Connect Your Projects")}
70+
connect_project_instruction = _(
71+
"To complete installation, please connect your Sentry and Vercel projects."
72+
)
73+
install_source_code_integration = _(
74+
"Install a [source code integration]({}) and configure your repositories."
75+
)
6676

6777
disable_dialog = {
68-
"actionText": "Visit Vercel",
69-
"body": "In order to uninstall this integration, you must go"
70-
" to Vercel and uninstall there by clicking 'Remove Configuration'.",
78+
"actionText": _("Visit Vercel"),
79+
"body": _(
80+
"In order to uninstall this integration, you must go"
81+
" to Vercel and uninstall there by clicking 'Remove Configuration'."
82+
),
7183
}
7284

7385

@@ -97,6 +109,21 @@ class VercelIntegration(IntegrationInstallation):
97109
def metadata(self):
98110
return self.model.metadata
99111

112+
def get_dynamic_display_information(self):
113+
organization = Organization.objects.get_from_cache(id=self.organization_id)
114+
source_code_link = absolute_uri(
115+
u"/settings/%s/integrations/?%s"
116+
% (organization.slug, urlencode({"category": "source code management"}))
117+
)
118+
return {
119+
"configure_integration": {
120+
"instructions": [
121+
connect_project_instruction,
122+
install_source_code_integration.format(source_code_link),
123+
]
124+
}
125+
}
126+
100127
def get_client(self):
101128
access_token = self.metadata["access_token"]
102129
if self.metadata["installation_type"] == "team":

src/sentry/static/sentry/app/components/events/interfaces/spans/spanDetail.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,6 @@ class SpanDetail extends React.Component<Props, State> {
108108
end,
109109
};
110110

111-
if (query.project.length === 0) {
112-
delete query.project;
113-
}
114-
115111
return api.requestPromise(url, {
116112
method: 'GET',
117113
query,

src/sentry/static/sentry/app/types/index.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,11 @@ export type Integration = {
858858
| 'born_as_bot'
859859
| 'migrated_to_bot';
860860
};
861+
dynamicDisplayInformation?: {
862+
configure_integration?: {
863+
instructions: string[];
864+
};
865+
};
861866
};
862867

863868
export type IntegrationExternalIssue = {

src/sentry/static/sentry/app/views/projectInstall/overview.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class ProjectInstallOverview extends AsyncComponent {
5757

5858
return (
5959
<div>
60-
<SentryDocumentTitle title={t('Error Tracking')} objSlug={projectId} />
60+
<SentryDocumentTitle title={t('Instrumentation')} objSlug={projectId} />
6161
<SettingsPageHeader title={t('Configure your application')} />
6262
<TextBlock>
6363
{t(

src/sentry/static/sentry/app/views/releasesV2/detail/releaseHeader.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ const ReleaseHeader = ({location, orgId, release, project, releaseMeta}: Props)
9292
</DeploysWrapper>
9393
</ReleaseStat>
9494
{hasHealthData && (
95-
<ReleaseStat label={t('Crashes')}>
95+
<ReleaseStat
96+
label={t('Crashes')}
97+
help={t('Crash means that user experienced an unhandled error')}
98+
>
9699
<Count value={sessionsCrashed} />
97100
</ReleaseStat>
98101
)}

src/sentry/static/sentry/app/views/releasesV2/detail/releaseStat.tsx

+17-3
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@ import React from 'react';
22
import styled from '@emotion/styled';
33

44
import space from 'app/styles/space';
5+
import QuestionTooltip from 'app/components/questionTooltip';
56

67
type Props = {
78
label: string;
89
children: React.ReactNode;
10+
help?: React.ReactNode;
911
};
1012

11-
const ReleaseStat = ({label, children}: Props) => (
13+
const ReleaseStat = ({label, children, help}: Props) => (
1214
<Wrapper>
13-
<Label>{label}</Label>
15+
<Label hasHelp={!!help}>
16+
{label}
17+
{help && <StyledQuestionTooltip title={help} size="xs" position="top" />}
18+
</Label>
1419
<Value>{children}</Value>
1520
</Wrapper>
1621
);
@@ -21,15 +26,24 @@ const Wrapper = styled('div')`
2126
}
2227
`;
2328

24-
const Label = styled('div')`
29+
const Label = styled('div')<{hasHelp: boolean}>`
2530
font-weight: 600;
2631
font-size: ${p => p.theme.fontSizeSmall};
2732
text-transform: uppercase;
2833
color: ${p => p.theme.gray500};
2934
line-height: 1.3;
3035
margin-bottom: ${space(0.25)};
3136
white-space: nowrap;
37+
display: flex;
38+
@media (min-width: ${p => p.theme.breakpoints[1]}) {
39+
justify-content: flex-end;
40+
}
41+
`;
42+
43+
const StyledQuestionTooltip = styled(QuestionTooltip)`
44+
margin-left: ${space(0.5)};
3245
`;
46+
3347
const Value = styled('div')`
3448
font-size: ${p => p.theme.fontSizeExtraLarge};
3549
color: ${p => p.theme.gray700};

src/sentry/static/sentry/app/views/settings/incidentRules/triggers/chart/index.tsx

+1-4
Original file line numberDiff line numberDiff line change
@@ -201,16 +201,13 @@ const ChartPlaceholder = styled(Placeholder)`
201201

202202
const StickyWrapper = styled('div')`
203203
position: sticky;
204-
top: 69px; /* Height of settings breadcrumb 69px */
204+
top: ${space(1)};
205205
z-index: ${p => p.theme.zIndex.dropdown - 1};
206-
background: rgba(255, 255, 255, 0.9);
207206
`;
208207

209208
const StyledPanel = styled(Panel)`
210209
/* Remove margin for the sticky window */
211210
margin-bottom: 0;
212-
/* Keep semi transparent background */
213-
background: none;
214211
`;
215212

216213
const StyledSelectControl = styled(SelectControl)`

src/sentry/static/sentry/app/views/settings/organizationIntegrations/configureIntegration.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import SettingsPageHeader from 'app/views/settings/components/settingsPageHeader
1616
import withOrganization from 'app/utils/withOrganization';
1717
import {Organization, Integration, IntegrationProvider} from 'app/types';
1818
import {trackIntegrationEvent} from 'app/utils/integrationUtil';
19+
import {singleLineRenderer} from 'app/utils/marked';
20+
import Alert from 'app/components/alert';
1921

2022
type RouteParams = {
2123
orgId: string;
@@ -125,6 +127,14 @@ class ConfigureIntegration extends AsyncView<Props, State> {
125127
</Form>
126128
)}
127129

130+
{integration.dynamicDisplayInformation?.configure_integration?.instructions.map(
131+
instruction => (
132+
<Alert type="info">
133+
<span dangerouslySetInnerHTML={{__html: singleLineRenderer(instruction)}} />
134+
</Alert>
135+
)
136+
)}
137+
128138
{provider && provider.features.includes('alert-rule') && (
129139
<IntegrationAlertRules integration={integration} />
130140
)}

src/sentry/static/sentry/app/views/settings/project/navigationConfiguration.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export default function getConfiguration({
108108
items: [
109109
{
110110
path: `${pathPrefix}/install/`,
111-
title: t('Error Tracking'),
111+
title: t('Instrumentation'),
112112
},
113113
{
114114
path: `${pathPrefix}/keys/`,

0 commit comments

Comments
 (0)