Issue #26 - Teams tab to show teams in your reporting chain
This commit is contained in:
Родитель
90c81d3229
Коммит
0f5c513170
32
README.md
32
README.md
|
@ -2,10 +2,40 @@
|
|||
|
||||
This is a Bugzilla dashboard that helps management determine Bugzilla components triaging status plus listing members of their reporting chain.
|
||||
|
||||
Only LDAP users are allowed to use this app.
|
||||
Only LDAP users are allowed to use this app. You can do development locally without an LDAP account, however, the app will only
|
||||
have fake org data. See the [Contribute](#contribute) section.
|
||||
|
||||
You can see the deployment in [here](http://bugzilla-management-dashboard.netlify.com/).
|
||||
|
||||
## Adding more teams
|
||||
|
||||
A team is a collection of components that can span various products and it is shown under the Teams tab.
|
||||
You can add new teams and make them show in the Teams tab by making changes to the [config](https://github.com/mozilla/bugzilla-dashboard/blob/master/src/config.js) file.
|
||||
|
||||
To add a team you need to modify `TEAMS_CONFIG` and an entry similar to this:
|
||||
|
||||
```javascript
|
||||
export const TEAMS_CONFIG = {
|
||||
domCore: {
|
||||
label: 'DOM Core',
|
||||
owner: 'someone@mozilla.com',
|
||||
product: ['Core'],
|
||||
component: [
|
||||
'DOM: Core & HTML', 'DOM: Events',
|
||||
'Editor', 'HTML: Parser', 'Selection', 'Serializers',
|
||||
'User events and focus handling',
|
||||
],
|
||||
},
|
||||
```
|
||||
|
||||
Here's how to configure it:
|
||||
|
||||
* `product` and `component` are parameters passed to the Bugzilla queries.
|
||||
* `owner` should match someone reporting to you.
|
||||
* Use their Bugzilla email rather than their LDAP
|
||||
* If the person does is not someone showing up on your Reportees tab it won't work
|
||||
* `label` is the name of the team
|
||||
|
||||
## Generate data
|
||||
|
||||
Until we have a backend, we need to regenerate certain files to bring the app up-to-date.
|
||||
|
|
|
@ -16,7 +16,7 @@ const styles = ({
|
|||
},
|
||||
});
|
||||
|
||||
const sortByComponentName = (a, b) => a.label - b.label;
|
||||
const sortByComponentName = (a, b) => a.label.localeCompare(b.label);
|
||||
|
||||
const BugzillaComponents = ({
|
||||
classes, title, bugzillaComponents, onComponentDetails,
|
||||
|
|
|
@ -21,7 +21,7 @@ const styles = ({
|
|||
},
|
||||
});
|
||||
|
||||
const sortByPersonName = (a, b) => (a.cn <= b.cn ? -1 : 1);
|
||||
const sortByPersonName = (a, b) => a.cn.localeCompare(b.cn);
|
||||
|
||||
const Reportees = ({
|
||||
classes, ldapEmail, partialOrg, onPersonDetails,
|
||||
|
|
|
@ -18,7 +18,7 @@ const config = {
|
|||
export const TEAMS_CONFIG = {
|
||||
domCore: {
|
||||
label: 'DOM Core',
|
||||
owner: 'someone@mozilla.com',
|
||||
owner: 'htsai@mozilla.com',
|
||||
product: ['Core'],
|
||||
component: [
|
||||
'DOM: Core & HTML', 'DOM: Events',
|
||||
|
@ -28,7 +28,7 @@ export const TEAMS_CONFIG = {
|
|||
},
|
||||
domFission: {
|
||||
label: 'DOM Fission',
|
||||
owner: 'manager@mozilla.com',
|
||||
owner: 'nkochar@mozilla.com',
|
||||
product: ['Core', 'Toolkit'],
|
||||
component: [
|
||||
'Document Navigation', 'XBL', 'XML', 'XPConnect', 'XSLT',
|
||||
|
@ -36,7 +36,7 @@ export const TEAMS_CONFIG = {
|
|||
},
|
||||
workerStoreage: {
|
||||
label: 'Worker and Storage',
|
||||
owner: 'manager@mozilla.com',
|
||||
owner: 'aoverholt@mozilla.com',
|
||||
product: ['Core', 'Toolkit'],
|
||||
component: [
|
||||
'DOM: IndexedDB', 'DOM: Push Notifications', 'DOM: Quota Manager',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { Component, Suspense } from 'react';
|
||||
import { Switch } from 'react-router-dom';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Spinner from '@mozilla-frontend-infra/components/Spinner';
|
||||
import PropsRoute from '../../components/PropsRoute';
|
||||
import AuthContext from '../../components/auth/AuthContext';
|
||||
import Header from '../../components/Header';
|
||||
|
@ -13,8 +14,10 @@ const BugzillaComponents = React.lazy(() => import('../../components/BugzillaCom
|
|||
const BugzillaComponentDetails = React.lazy(() => import('../../components/BugzillaComponentDetails'));
|
||||
const PersonDetails = React.lazy(() => import('../../components/PersonDetails'));
|
||||
const Reportees = React.lazy(() => import('../../components/Reportees'));
|
||||
const Teams = React.lazy(() => import('../Teams'));
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
doneLoading: false,
|
||||
bugzillaComponents: {},
|
||||
partialOrg: undefined,
|
||||
teamComponents: {},
|
||||
|
@ -147,26 +150,27 @@ class MainContainer extends Component {
|
|||
getBugzillaOwners(),
|
||||
this.getReportees(userSession, ldapEmail),
|
||||
]);
|
||||
this.teamsData();
|
||||
this.teamsData(partialOrg);
|
||||
this.bugzillaComponents(bzOwners, partialOrg);
|
||||
this.setState({ doneLoading: true });
|
||||
}
|
||||
|
||||
async teamsData() {
|
||||
const teamComponents = Object.assign({}, TEAMS_CONFIG);
|
||||
// This will cause the teams to be displayed before having any metrics
|
||||
this.setState({ teamComponents });
|
||||
Object.entries(teamComponents).map(async ([teamKey, teamInfo]) => {
|
||||
const team = {
|
||||
teamKey,
|
||||
...teamInfo,
|
||||
metrics: {},
|
||||
};
|
||||
const { product, component } = teamInfo;
|
||||
await Promise.all(Object.keys(BZ_QUERIES).map(async (metric) => {
|
||||
team.metrics[metric] = await getBugsCountAndLink(product, component, metric);
|
||||
}));
|
||||
teamComponents[teamKey] = team;
|
||||
this.setState({ teamComponents });
|
||||
async teamsData(partialOrg) {
|
||||
const teamComponents = {};
|
||||
Object.entries(TEAMS_CONFIG).map(async ([teamKey, teamInfo]) => {
|
||||
if (partialOrg[teamInfo.owner]) {
|
||||
const team = {
|
||||
teamKey,
|
||||
...teamInfo,
|
||||
metrics: {},
|
||||
};
|
||||
const { product, component } = teamInfo;
|
||||
await Promise.all(Object.keys(BZ_QUERIES).map(async (metric) => {
|
||||
team.metrics[metric] = await getBugsCountAndLink(product, component, metric);
|
||||
}));
|
||||
teamComponents[teamKey] = team;
|
||||
this.setState({ teamComponents });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -211,6 +215,7 @@ class MainContainer extends Component {
|
|||
|
||||
render() {
|
||||
const {
|
||||
doneLoading,
|
||||
componentDetails,
|
||||
personDetails,
|
||||
bugzillaComponents,
|
||||
|
@ -269,12 +274,13 @@ class MainContainer extends Component {
|
|||
)}
|
||||
<PropsRoute
|
||||
path="/teams"
|
||||
component={BugzillaComponents}
|
||||
component={Teams}
|
||||
bugzillaComponents={Object.values(teamComponents)}
|
||||
onComponentDetails={this.handleShowComponentDetails}
|
||||
/>
|
||||
</Switch>
|
||||
</Suspense>
|
||||
{!doneLoading && <Spinner loading /> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import BugzillaComponents from '../../components/BugzillaComponents';
|
||||
|
||||
const styles = {
|
||||
message: {
|
||||
margin: '0 0 1rem 0',
|
||||
},
|
||||
};
|
||||
|
||||
const Teams = ({ classes, ...rest }) => (
|
||||
<React.Fragment>
|
||||
<div className={classes.message}>
|
||||
<span>If you want to change what shows up in this page follow </span>
|
||||
<a href="https://github.com/mozilla/bugzilla-dashboard#generate-data">these instructions</a>
|
||||
</div>
|
||||
<BugzillaComponents {...rest} />
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
export default withStyles(styles)(Teams);
|
|
@ -28,6 +28,37 @@ exports[`renders components 1`] = `
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-4"
|
||||
name="Core::DOM: Core & HTML"
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="MuiSvgIcon-root-6 DrilldownIcon-icon-5"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"
|
||||
/>
|
||||
<path
|
||||
d="M0 0h24v24H0z"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
Core::DOM: Core & HTML
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
|
@ -90,37 +121,6 @@ exports[`renders components 1`] = `
|
|||
Core::JavaScript Engine
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-4"
|
||||
name="Core::DOM: Core & HTML"
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="MuiSvgIcon-root-6 DrilldownIcon-icon-5"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"
|
||||
/>
|
||||
<path
|
||||
d="M0 0h24v24H0z"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
Core::DOM: Core & HTML
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
|
|
Загрузка…
Ссылка в новой задаче