Skip to content

Commit

Permalink
ref(ts): Refactor Incident Details to typescript (#14510)
Browse files Browse the repository at this point in the history
typescript all the things
  • Loading branch information
billyvg authored Aug 27, 2019
1 parent 84d8051 commit c5efd5b
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 122 deletions.
2 changes: 1 addition & 1 deletion src/sentry/static/sentry/app/routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1041,7 +1041,7 @@ function routes() {
<Route
path=":incidentId/"
componentPromise={() =>
import(/* webpackChunkName: "OrganizationIncidentDetails" */ 'app/views/incidents/details')
import(/* webpackChunkName: "IncidentDetails" */ 'app/views/incidents/details')
}
component={errorHandler(LazyLoad)}
/>
Expand Down
11 changes: 11 additions & 0 deletions src/sentry/static/sentry/app/types/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,14 @@ export type EventView = {
tags: string[];
columnWidths: string[];
};

export type Repository = {
dateCreated: string;
externalSlug: string;
id: string;
integrationId: string;
name: string;
provider: {id: string; name: string};
status: string;
url: string;
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {Params} from 'react-router/lib/Router';
import React from 'react';
import styled from 'react-emotion';

Expand All @@ -10,7 +11,6 @@ import NavTabs from 'app/components/navTabs';
import Placeholder from 'app/components/placeholder';
import Projects from 'app/utils/projects';
import SeenByList from 'app/components/seenByList';
import SentryTypes from 'app/sentryTypes';
import SideHeader from 'app/views/incidents/details/sideHeader';
import space from 'app/styles/space';
import theme from 'app/utils/theme';
Expand All @@ -19,16 +19,17 @@ import Activity from './activity';
import RelatedIssues from './relatedIssues';
import Suspects from './suspects';

export default class DetailsBody extends React.Component {
static propTypes = {
incident: SentryTypes.Incident,
};
import {Incident} from '../types';

type Props = {
params: Params;
incident?: Incident;
};

export default class DetailsBody extends React.Component<Props> {
render() {
const {params, incident} = this.props;

// Considered loading when there is no incident object
const loading = !incident;
return (
<StyledPageContent>
<Main>
Expand All @@ -51,15 +52,15 @@ export default class DetailsBody extends React.Component {
<Activity
params={params}
incident={incident}
incidentStatus={!loading ? incident.status : null}
incidentStatus={!!incident ? incident.status : null}
/>
</PageContent>
</Main>
<Sidebar>
<PageContent>
<SideHeader loading={loading}>{t('Events in Incident')}</SideHeader>
<SideHeader loading={!incident}>{t('Events in Incident')}</SideHeader>

{!loading ? (
{incident ? (
<Chart
data={incident.eventStats.data}
detected={incident.dateDetected}
Expand All @@ -70,11 +71,11 @@ export default class DetailsBody extends React.Component {
)}

<div>
<SideHeader loading={loading}>
{t('Projects Affected')} ({!loading ? incident.projects.length : '-'})
<SideHeader loading={!incident}>
{t('Projects Affected')} ({incident ? incident.projects.length : '-'})
</SideHeader>

{!loading && (
{incident && (
<div>
<Projects slugs={incident.projects} orgId={params.orgId}>
{({projects}) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import PropTypes from 'prop-types';
import React from 'react';
import moment from 'moment';

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

type Data = [number, {count: number}[]][];

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

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

export default class Chart extends React.PureComponent {
static propTypes = {
data: PropTypes.arrayOf(
PropTypes.arrayOf(
PropTypes.oneOfType([
PropTypes.number,
PropTypes.arrayOf(PropTypes.shape({count: PropTypes.number})),
])
)
),
detected: PropTypes.string,
closed: PropTypes.string,
};
type Props = {
data: Data;
detected: string;
closed: string;
};

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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Params} from 'react-router/lib/Router';
import {Link} from 'react-router';
import PropTypes from 'prop-types';
import React from 'react';
import moment from 'moment';
import styled from 'react-emotion';
Expand All @@ -14,23 +14,25 @@ import InlineSvg from 'app/components/inlineSvg';
import LoadingError from 'app/components/loadingError';
import MenuItem from 'app/components/menuItem';
import PageHeading from 'app/components/pageHeading';
import SentryTypes from 'app/sentryTypes';
import SubscribeButton from 'app/components/subscribeButton';
import space from 'app/styles/space';
import getDynamicText from 'app/utils/getDynamicText';

import {isOpen} from '../utils';
import Status from '../status';

export default class DetailsHeader extends React.Component {
static propTypes = {
incident: SentryTypes.Incident,
params: PropTypes.object.isRequired,
hasIncidentDetailsError: PropTypes.bool.isRequired,
onSubscriptionChange: PropTypes.func.isRequired,
onStatusChange: PropTypes.func.isRequired,
};

import {Incident} from '../types';

type Props = {
className?: string;
hasIncidentDetailsError: boolean;
// Can be undefined when loading
incident?: Incident;
onSubscriptionChange: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
onStatusChange: (eventKey: any) => void;
params: Params;
};

export default class DetailsHeader extends React.Component<Props> {
renderStatus() {
const {incident, onStatusChange} = this.props;

Expand Down Expand Up @@ -59,15 +61,18 @@ export default class DetailsHeader extends React.Component {
render() {
const {hasIncidentDetailsError, incident, params, onSubscriptionChange} = this.props;
const isIncidentReady = !!incident && !hasIncidentDetailsError;
const eventLink = incident && {
pathname: `/organizations/${params.orgId}/events/`,

// Note we don't have project selector on here so there should be
// no query params to forward
query: {
group: incident.groups,
},
};
const eventLink = incident
? {
pathname: `/organizations/${params.orgId}/events/`,

// Note we don't have project selector on here so there should be
// no query params to forward
query: {
group: incident.groups,
},
}
: '';

const dateStarted = incident && moment(incident.dateStarted).format('LL');
const duration =
incident &&
Expand All @@ -93,7 +98,7 @@ export default class DetailsHeader extends React.Component {
)}
</Breadcrumb>
<IncidentTitle data-test-id="incident-title" loading={!isIncidentReady}>
{isIncidentReady ? incident.title : 'Loading'}
{incident && !hasIncidentDetailsError ? incident.title : 'Loading'}
</IncidentTitle>
</PageHeading>
</HeaderItem>
Expand All @@ -107,23 +112,23 @@ export default class DetailsHeader extends React.Component {
</HeaderItem>
<HeaderItem>
<ItemTitle>{t('Duration')}</ItemTitle>
{isIncidentReady && (
{incident && (
<ItemValue>
<Duration seconds={getDynamicText({value: duration, fixed: 1200})} />
</ItemValue>
)}
</HeaderItem>
<HeaderItem>
<ItemTitle>{t('Users affected')}</ItemTitle>
{isIncidentReady && (
{incident && (
<ItemValue>
<Count value={incident.uniqueUsers} />
</ItemValue>
)}
</HeaderItem>
<HeaderItem>
<ItemTitle>{t('Total events')}</ItemTitle>
{isIncidentReady && (
{incident && (
<ItemValue>
<Count value={incident.totalEvents} />
<OpenLink to={eventLink}>
Expand Down Expand Up @@ -198,7 +203,7 @@ const Breadcrumb = styled('div')`
margin-bottom: ${space(1)};
`;

const IncidentTitle = styled('div')`
const IncidentTitle = styled('div')<{loading: boolean}>`
${p => p.loading && 'opacity: 0'};
`;

Expand Down
Loading

0 comments on commit c5efd5b

Please sign in to comment.