Skip to content

Commit 4fd27ae

Browse files
committed
feat(ui): Add "Projects Affected" section in Incidents [WIP]
List projects affected inside of an Incident.
1 parent a2614bf commit 4fd27ae

File tree

3 files changed

+119
-112
lines changed

3 files changed

+119
-112
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import {partition} from 'lodash';
2+
import PropTypes from 'prop-types';
3+
import React from 'react';
4+
5+
import SentryTypes from 'app/sentryTypes';
6+
import withApi from 'app/utils/withApi';
7+
import withProjects from 'app/utils/withProjects';
8+
9+
class Projects extends React.Component {
10+
static propTypes = {
11+
api: PropTypes.object.isRequired,
12+
orgId: PropTypes.string.isRequired,
13+
slugs: PropTypes.arrayOf(PropTypes.string).isRequired,
14+
projects: PropTypes.arrayOf(SentryTypes.Project).isRequired,
15+
};
16+
17+
state = {
18+
fetchedProjects: [],
19+
projectsFromStore: [],
20+
fetching: false,
21+
};
22+
23+
componentDidMount() {
24+
this.getDetails();
25+
}
26+
27+
componentDidUpdate() {}
28+
29+
loaded = false;
30+
fetchQueue = new Set();
31+
32+
getDetails() {
33+
const {slugs, projects} = this.props;
34+
35+
// check if projects store has any items, if not we should wait
36+
if (!projects.length) {
37+
return;
38+
}
39+
40+
this.loaded = true;
41+
42+
const [inStore, notInStore] = partition(slugs, slug =>
43+
[].find(project => project.slug === slug)
44+
);
45+
46+
// Check `projects` (from store)
47+
const projectsFromStore = inStore.map(slug =>
48+
projects.find(project => project.slug === slug)
49+
);
50+
51+
this.setState({
52+
projectsFromStore,
53+
});
54+
55+
notInStore.forEach(slug => this.fetchQueue.add(slug));
56+
57+
// placeholders
58+
this.setState({
59+
fetchedProjects: notInStore.map(slug => ({slug})),
60+
});
61+
62+
this.fetchProjects();
63+
}
64+
65+
async fetchProjects() {
66+
const {api, orgId} = this.props;
67+
68+
if (!this.fetchQueue.size) {
69+
return;
70+
}
71+
72+
this.setState({
73+
fetching: true,
74+
});
75+
76+
await new Promise(resolve => setTimeout(resolve, 2500));
77+
const results = await Promise.all(
78+
Array.from(this.fetchQueue).map(slug =>
79+
api.requestPromise(`/organizations/${orgId}/projects/`, {
80+
query: {
81+
query: `slug:${slug}`,
82+
},
83+
})
84+
)
85+
);
86+
this.setState({
87+
fetchedProjects: results.map(([result]) => result),
88+
fetching: false,
89+
});
90+
}
91+
92+
render() {
93+
const {slugs, children} = this.props;
94+
return children({
95+
loaded: this.loaded,
96+
projects: this.loaded
97+
? [...this.state.fetchedProjects, ...this.state.projectsFromStore]
98+
: slugs.map(slug => ({slug})),
99+
fetching: this.state.fetching,
100+
});
101+
}
102+
}
103+
104+
export default withProjects(withApi(Projects));

src/sentry/static/sentry/app/utils/withProjectDetails.jsx

Lines changed: 0 additions & 108 deletions
This file was deleted.

src/sentry/static/sentry/app/views/organizationIncidents/details/body.jsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import LineChart from 'app/components/charts/lineChart';
99
import Link from 'app/components/links/link';
1010
import MarkPoint from 'app/components/charts/components/markPoint';
1111
import NavTabs from 'app/components/navTabs';
12+
import Projects from 'app/utils/projects';
1213
import SeenByList from 'app/components/seenByList';
1314
import SentryTypes from 'app/sentryTypes';
1415
import space from 'app/styles/space';
@@ -112,7 +113,7 @@ export default class DetailsBody extends React.Component {
112113
</Main>
113114
<Sidebar>
114115
<PageContent>
115-
{incident && (
116+
{incident ? (
116117
<LineChart
117118
isGroupedByDate
118119
series={[
@@ -141,6 +142,8 @@ export default class DetailsBody extends React.Component {
141142
},
142143
]}
143144
/>
145+
) : (
146+
<ChartPlaceholder />
144147
)}
145148

146149
<IncidentsSuspects suspects={[]} />
@@ -152,9 +155,13 @@ export default class DetailsBody extends React.Component {
152155

153156
{incident && (
154157
<div>
155-
{incident.projects.map(project => {
156-
return <IdBadge key={project} project={{slug: project}} />;
157-
})}
158+
<Projects slugs={incident.projects} orgId={params.orgId}>
159+
{({projects, fetching}) => {
160+
return projects.map(project => (
161+
<StyledIdBadge key={project.slug} project={project} />
162+
));
163+
}}
164+
</Projects>
158165
</div>
159166
)}
160167
</div>
@@ -217,3 +224,7 @@ const SidebarHeading = styled('h6')`
217224
margin: ${space(2)} 0 ${space(1)} 0;
218225
text-transform: uppercase;
219226
`;
227+
228+
const StyledIdBadge = styled(IdBadge)`
229+
margin-bottom: ${space(1)};
230+
`;

0 commit comments

Comments
 (0)