Skip to content

Commit c5efd5b

Browse files
authored
ref(ts): Refactor Incident Details to typescript (#14510)
typescript all the things
1 parent 84d8051 commit c5efd5b

File tree

12 files changed

+169
-122
lines changed

12 files changed

+169
-122
lines changed

src/sentry/static/sentry/app/routes.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,7 @@ function routes() {
10411041
<Route
10421042
path=":incidentId/"
10431043
componentPromise={() =>
1044-
import(/* webpackChunkName: "OrganizationIncidentDetails" */ 'app/views/incidents/details')
1044+
import(/* webpackChunkName: "IncidentDetails" */ 'app/views/incidents/details')
10451045
}
10461046
component={errorHandler(LazyLoad)}
10471047
/>

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,14 @@ export type EventView = {
291291
tags: string[];
292292
columnWidths: string[];
293293
};
294+
295+
export type Repository = {
296+
dateCreated: string;
297+
externalSlug: string;
298+
id: string;
299+
integrationId: string;
300+
name: string;
301+
provider: {id: string; name: string};
302+
status: string;
303+
url: string;
304+
};

src/sentry/static/sentry/app/views/incidents/details/body.jsx renamed to src/sentry/static/sentry/app/views/incidents/details/body.tsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {Params} from 'react-router/lib/Router';
12
import React from 'react';
23
import styled from 'react-emotion';
34

@@ -10,7 +11,6 @@ import NavTabs from 'app/components/navTabs';
1011
import Placeholder from 'app/components/placeholder';
1112
import Projects from 'app/utils/projects';
1213
import SeenByList from 'app/components/seenByList';
13-
import SentryTypes from 'app/sentryTypes';
1414
import SideHeader from 'app/views/incidents/details/sideHeader';
1515
import space from 'app/styles/space';
1616
import theme from 'app/utils/theme';
@@ -19,16 +19,17 @@ import Activity from './activity';
1919
import RelatedIssues from './relatedIssues';
2020
import Suspects from './suspects';
2121

22-
export default class DetailsBody extends React.Component {
23-
static propTypes = {
24-
incident: SentryTypes.Incident,
25-
};
22+
import {Incident} from '../types';
2623

24+
type Props = {
25+
params: Params;
26+
incident?: Incident;
27+
};
28+
29+
export default class DetailsBody extends React.Component<Props> {
2730
render() {
2831
const {params, incident} = this.props;
2932

30-
// Considered loading when there is no incident object
31-
const loading = !incident;
3233
return (
3334
<StyledPageContent>
3435
<Main>
@@ -51,15 +52,15 @@ export default class DetailsBody extends React.Component {
5152
<Activity
5253
params={params}
5354
incident={incident}
54-
incidentStatus={!loading ? incident.status : null}
55+
incidentStatus={!!incident ? incident.status : null}
5556
/>
5657
</PageContent>
5758
</Main>
5859
<Sidebar>
5960
<PageContent>
60-
<SideHeader loading={loading}>{t('Events in Incident')}</SideHeader>
61+
<SideHeader loading={!incident}>{t('Events in Incident')}</SideHeader>
6162

62-
{!loading ? (
63+
{incident ? (
6364
<Chart
6465
data={incident.eventStats.data}
6566
detected={incident.dateDetected}
@@ -70,11 +71,11 @@ export default class DetailsBody extends React.Component {
7071
)}
7172

7273
<div>
73-
<SideHeader loading={loading}>
74-
{t('Projects Affected')} ({!loading ? incident.projects.length : '-'})
74+
<SideHeader loading={!incident}>
75+
{t('Projects Affected')} ({incident ? incident.projects.length : '-'})
7576
</SideHeader>
7677

77-
{!loading && (
78+
{incident && (
7879
<div>
7980
<Projects slugs={incident.projects} orgId={params.orgId}>
8081
{({projects}) => {

src/sentry/static/sentry/app/views/incidents/details/chart.jsx renamed to src/sentry/static/sentry/app/views/incidents/details/chart.tsx

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import PropTypes from 'prop-types';
21
import React from 'react';
32
import moment from 'moment';
43

@@ -9,6 +8,8 @@ import MarkPoint from 'app/components/charts/components/markPoint';
98
import closedSymbol from './closedSymbol';
109
import detectedSymbol from './detectedSymbol';
1110

11+
type Data = [number, {count: number}[]][];
12+
1213
/**
1314
* So we'll have to see how this looks with real data, but echarts requires
1415
* an explicit (x,y) value to draw a symbol (incident detected/closed bubble).
@@ -18,8 +19,11 @@ import detectedSymbol from './detectedSymbol';
1819
* AFAICT we can't give it an x-axis value and have it draw on the line,
1920
* so we probably need to calculate the y-axis value ourselves if we want it placed
2021
* at the exact time.
22+
*
23+
* @param data Data array
24+
* @param needle the target timestamp
2125
*/
22-
function getNearbyIndex(data, needle) {
26+
function getNearbyIndex(data: Data, needle: number) {
2327
// `data` is sorted, return the first index whose value (timestamp) is > `needle`
2428
const index = data.findIndex(([ts]) => ts > needle);
2529

@@ -31,20 +35,13 @@ function getNearbyIndex(data, needle) {
3135
return index !== -1 ? index - 1 : data.length - 1;
3236
}
3337

34-
export default class Chart extends React.PureComponent {
35-
static propTypes = {
36-
data: PropTypes.arrayOf(
37-
PropTypes.arrayOf(
38-
PropTypes.oneOfType([
39-
PropTypes.number,
40-
PropTypes.arrayOf(PropTypes.shape({count: PropTypes.number})),
41-
])
42-
)
43-
),
44-
detected: PropTypes.string,
45-
closed: PropTypes.string,
46-
};
38+
type Props = {
39+
data: Data;
40+
detected: string;
41+
closed: string;
42+
};
4743

44+
export default class Chart extends React.PureComponent<Props> {
4845
render() {
4946
const {data, detected, closed} = this.props;
5047

src/sentry/static/sentry/app/views/incidents/details/header.jsx renamed to src/sentry/static/sentry/app/views/incidents/details/header.tsx

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import {Params} from 'react-router/lib/Router';
12
import {Link} from 'react-router';
2-
import PropTypes from 'prop-types';
33
import React from 'react';
44
import moment from 'moment';
55
import styled from 'react-emotion';
@@ -14,23 +14,25 @@ import InlineSvg from 'app/components/inlineSvg';
1414
import LoadingError from 'app/components/loadingError';
1515
import MenuItem from 'app/components/menuItem';
1616
import PageHeading from 'app/components/pageHeading';
17-
import SentryTypes from 'app/sentryTypes';
1817
import SubscribeButton from 'app/components/subscribeButton';
1918
import space from 'app/styles/space';
2019
import getDynamicText from 'app/utils/getDynamicText';
2120

2221
import {isOpen} from '../utils';
2322
import Status from '../status';
24-
25-
export default class DetailsHeader extends React.Component {
26-
static propTypes = {
27-
incident: SentryTypes.Incident,
28-
params: PropTypes.object.isRequired,
29-
hasIncidentDetailsError: PropTypes.bool.isRequired,
30-
onSubscriptionChange: PropTypes.func.isRequired,
31-
onStatusChange: PropTypes.func.isRequired,
32-
};
33-
23+
import {Incident} from '../types';
24+
25+
type Props = {
26+
className?: string;
27+
hasIncidentDetailsError: boolean;
28+
// Can be undefined when loading
29+
incident?: Incident;
30+
onSubscriptionChange: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
31+
onStatusChange: (eventKey: any) => void;
32+
params: Params;
33+
};
34+
35+
export default class DetailsHeader extends React.Component<Props> {
3436
renderStatus() {
3537
const {incident, onStatusChange} = this.props;
3638

@@ -59,15 +61,18 @@ export default class DetailsHeader extends React.Component {
5961
render() {
6062
const {hasIncidentDetailsError, incident, params, onSubscriptionChange} = this.props;
6163
const isIncidentReady = !!incident && !hasIncidentDetailsError;
62-
const eventLink = incident && {
63-
pathname: `/organizations/${params.orgId}/events/`,
64-
65-
// Note we don't have project selector on here so there should be
66-
// no query params to forward
67-
query: {
68-
group: incident.groups,
69-
},
70-
};
64+
const eventLink = incident
65+
? {
66+
pathname: `/organizations/${params.orgId}/events/`,
67+
68+
// Note we don't have project selector on here so there should be
69+
// no query params to forward
70+
query: {
71+
group: incident.groups,
72+
},
73+
}
74+
: '';
75+
7176
const dateStarted = incident && moment(incident.dateStarted).format('LL');
7277
const duration =
7378
incident &&
@@ -93,7 +98,7 @@ export default class DetailsHeader extends React.Component {
9398
)}
9499
</Breadcrumb>
95100
<IncidentTitle data-test-id="incident-title" loading={!isIncidentReady}>
96-
{isIncidentReady ? incident.title : 'Loading'}
101+
{incident && !hasIncidentDetailsError ? incident.title : 'Loading'}
97102
</IncidentTitle>
98103
</PageHeading>
99104
</HeaderItem>
@@ -107,23 +112,23 @@ export default class DetailsHeader extends React.Component {
107112
</HeaderItem>
108113
<HeaderItem>
109114
<ItemTitle>{t('Duration')}</ItemTitle>
110-
{isIncidentReady && (
115+
{incident && (
111116
<ItemValue>
112117
<Duration seconds={getDynamicText({value: duration, fixed: 1200})} />
113118
</ItemValue>
114119
)}
115120
</HeaderItem>
116121
<HeaderItem>
117122
<ItemTitle>{t('Users affected')}</ItemTitle>
118-
{isIncidentReady && (
123+
{incident && (
119124
<ItemValue>
120125
<Count value={incident.uniqueUsers} />
121126
</ItemValue>
122127
)}
123128
</HeaderItem>
124129
<HeaderItem>
125130
<ItemTitle>{t('Total events')}</ItemTitle>
126-
{isIncidentReady && (
131+
{incident && (
127132
<ItemValue>
128133
<Count value={incident.totalEvents} />
129134
<OpenLink to={eventLink}>
@@ -198,7 +203,7 @@ const Breadcrumb = styled('div')`
198203
margin-bottom: ${space(1)};
199204
`;
200205

201-
const IncidentTitle = styled('div')`
206+
const IncidentTitle = styled('div')<{loading: boolean}>`
202207
${p => p.loading && 'opacity: 0'};
203208
`;
204209

0 commit comments

Comments
 (0)