Use routing to determine view instead of internal state (#60)
* The different tabs now have an associated route (e.g. `/reportees`) * Use `NavLink` within `Tab` to properly support routes * All of the above removes the need to keep track what to view via the state of the component * Remove `MainView` component and include it within the `Main` view * Create & update more tests * Add React.lazy and Suspense to lazy load components depending on the view
This commit is contained in:
Родитель
2c1ce29bad
Коммит
d1ea227104
|
@ -1,7 +1,12 @@
|
|||
import { hot } from 'react-hot-loader';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BrowserRouter, Switch, Route } from 'react-router-dom';
|
||||
import {
|
||||
BrowserRouter,
|
||||
Switch,
|
||||
Redirect,
|
||||
Route,
|
||||
} from 'react-router-dom';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import ErrorPanel from '@mozilla-frontend-infra/components/ErrorPanel';
|
||||
import Spinner from '@mozilla-frontend-infra/components/Spinner';
|
||||
|
@ -82,12 +87,15 @@ class App extends React.Component {
|
|||
{authReady ? (
|
||||
<AuthContext.Provider value={this.authController}>
|
||||
<Switch>
|
||||
<PropsRoute path="/" exact component={Main} />
|
||||
<Route path="/" exact>
|
||||
<Redirect to="/reportees" />
|
||||
</Route>
|
||||
<PropsRoute
|
||||
path={config.redirectRoute}
|
||||
component={Auth0Login}
|
||||
setUserSession={this.authController.setUserSession}
|
||||
/>
|
||||
<PropsRoute path="/" component={Main} />
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
</AuthContext.Provider>
|
||||
|
|
|
@ -5,6 +5,7 @@ import AppBar from '@material-ui/core/AppBar';
|
|||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import CredentialsMenu from '../../views/CredentialsMenu';
|
||||
|
||||
const styles = theme => ({
|
||||
|
@ -19,9 +20,9 @@ const Header = ({ classes, selectedTabIndex, handleTabChange }) => (
|
|||
<AppBar position="static">
|
||||
<Toolbar className={classes.styledToolbar}>
|
||||
<Tabs value={selectedTabIndex} onChange={handleTabChange}>
|
||||
<Tab label="Reportees" />
|
||||
<Tab label="Teams" />
|
||||
<Tab label="Components" />
|
||||
<Tab label="Reportees" component={NavLink} to="reportees" />
|
||||
<Tab label="Teams" component={NavLink} to="teams" />
|
||||
<Tab label="Components" component={NavLink} to="components" />
|
||||
</Tabs>
|
||||
<CredentialsMenu />
|
||||
</Toolbar>
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import BugzillaComponents from '../BugzillaComponents';
|
||||
import Reportees from '../Reportees';
|
||||
|
||||
class MainView extends React.Component {
|
||||
renderTabContents() {
|
||||
const {
|
||||
ldapEmail, partialOrg, onPersonDetails, teamComponents,
|
||||
bugzillaComponents, onComponentDetails, selectedTabIndex,
|
||||
} = this.props;
|
||||
switch (selectedTabIndex) {
|
||||
case 0: {
|
||||
return (
|
||||
<Reportees
|
||||
ldapEmail={ldapEmail}
|
||||
partialOrg={partialOrg}
|
||||
onPersonDetails={onPersonDetails}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case 1: {
|
||||
return (
|
||||
<BugzillaComponents
|
||||
bugzillaComponents={teamComponents}
|
||||
onComponentDetails={onComponentDetails}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case 2: {
|
||||
return (
|
||||
<BugzillaComponents
|
||||
bugzillaComponents={bugzillaComponents}
|
||||
onComponentDetails={onComponentDetails}
|
||||
/>
|
||||
);
|
||||
}
|
||||
default: {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.renderTabContents();
|
||||
}
|
||||
}
|
||||
|
||||
MainView.propTypes = {
|
||||
ldapEmail: PropTypes.string.isRequired,
|
||||
partialOrg: PropTypes.shape({}).isRequired,
|
||||
bugzillaComponents: PropTypes.arrayOf(PropTypes.shape({})),
|
||||
teamComponents: PropTypes.arrayOf(PropTypes.shape({})),
|
||||
onComponentDetails: PropTypes.func.isRequired,
|
||||
onPersonDetails: PropTypes.func.isRequired,
|
||||
selectedTabIndex: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
MainView.defaultProps = {
|
||||
bugzillaComponents: [],
|
||||
teamComponents: [],
|
||||
};
|
||||
|
||||
export default MainView;
|
|
@ -1,22 +1,32 @@
|
|||
import React, { Component } from 'react';
|
||||
import React, { Component, Suspense } from 'react';
|
||||
import { Switch } from 'react-router-dom';
|
||||
import PropsRoute from '../../components/PropsRoute';
|
||||
import AuthContext from '../../components/auth/AuthContext';
|
||||
import Header from '../../components/Header';
|
||||
import MainView from '../../components/MainView';
|
||||
import BugzillaComponentDetails from '../../components/BugzillaComponentDetails';
|
||||
import PersonDetails from '../../components/PersonDetails';
|
||||
import getAllReportees from '../../utils/getAllReportees';
|
||||
import getBugzillaOwners from '../../utils/getBugzillaOwners';
|
||||
import getBugsCountAndLink from '../../utils/bugzilla/getBugsCountAndLink';
|
||||
import METRICS from '../../utils/bugzilla/metrics';
|
||||
import TEAMS_CONFIG from '../../teamsConfig';
|
||||
|
||||
const BugzillaComponents = React.lazy(() => import('../../components/BugzillaComponents'));
|
||||
const BugzillaComponentDetails = React.lazy(() => import('../../components/BugzillaComponentDetails'));
|
||||
const PersonDetails = React.lazy(() => import('../../components/PersonDetails'));
|
||||
const Reportees = React.lazy(() => import('../../components/Reportees'));
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
bugzillaComponents: {},
|
||||
partialOrg: undefined,
|
||||
teamComponents: {},
|
||||
selectedTabIndex: 0,
|
||||
showComponent: undefined,
|
||||
showPerson: undefined,
|
||||
componentDetails: undefined,
|
||||
personDetails: undefined,
|
||||
};
|
||||
|
||||
const PATHNAME_TO_TAB_INDEX = {
|
||||
'/reportees': 0,
|
||||
'/teams': 1,
|
||||
'/components': 2,
|
||||
};
|
||||
|
||||
class MainContainer extends Component {
|
||||
|
@ -26,6 +36,9 @@ class MainContainer extends Component {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { location } = this.props;
|
||||
// This guarantees that we load the right tab based on the URL's pathname
|
||||
this.state.selectedTabIndex = PATHNAME_TO_TAB_INDEX[location.pathname] || 0;
|
||||
this.handleShowComponentDetails = this.handleShowComponentDetails.bind(this);
|
||||
this.handleShowPersonDetails = this.handleShowPersonDetails.bind(this);
|
||||
this.handleComponentBackToMenu = this.handleComponentBackToMenu.bind(this);
|
||||
|
@ -59,14 +72,18 @@ class MainContainer extends Component {
|
|||
return partialOrg;
|
||||
}
|
||||
|
||||
handleChangeSelectedTab = (event, selectedTabIndex) => {
|
||||
this.setState({ selectedTabIndex });
|
||||
};
|
||||
|
||||
handleUserSessionChanged = () => {
|
||||
this.fetchData();
|
||||
};
|
||||
|
||||
handleNavigateAndClear = (_, selectedTabIndex) => {
|
||||
this.setState({
|
||||
componentDetails: undefined,
|
||||
personDetails: undefined,
|
||||
selectedTabIndex,
|
||||
});
|
||||
};
|
||||
|
||||
fetchData() {
|
||||
const { context } = this;
|
||||
const userSession = context && context.getUserSession();
|
||||
|
@ -155,14 +172,14 @@ class MainContainer extends Component {
|
|||
// property 'team' to distinguish a component from a set of components
|
||||
if (teamKey) {
|
||||
this.setState(prevState => ({
|
||||
showComponent: {
|
||||
componentDetails: {
|
||||
title: prevState.teamComponents[teamKey].label,
|
||||
...prevState.teamComponents[teamKey],
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
this.setState(prevState => ({
|
||||
showComponent: {
|
||||
componentDetails: {
|
||||
title: componentKey,
|
||||
...prevState.bugzillaComponents[componentKey],
|
||||
},
|
||||
|
@ -174,22 +191,22 @@ class MainContainer extends Component {
|
|||
event.preventDefault();
|
||||
const { partialOrg } = this.state;
|
||||
this.setState({
|
||||
showPerson: partialOrg[properties.ldapEmail],
|
||||
personDetails: partialOrg[properties.ldapEmail],
|
||||
});
|
||||
}
|
||||
|
||||
handleComponentBackToMenu(event) {
|
||||
event.preventDefault();
|
||||
this.setState({
|
||||
showComponent: undefined,
|
||||
showPerson: undefined,
|
||||
componentDetails: undefined,
|
||||
personDetails: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
showComponent,
|
||||
showPerson,
|
||||
componentDetails,
|
||||
personDetails,
|
||||
bugzillaComponents,
|
||||
ldapEmail,
|
||||
partialOrg,
|
||||
|
@ -203,34 +220,53 @@ class MainContainer extends Component {
|
|||
<div>
|
||||
<Header
|
||||
selectedTabIndex={selectedTabIndex}
|
||||
handleTabChange={this.handleChangeSelectedTab}
|
||||
handleTabChange={this.handleNavigateAndClear}
|
||||
/>
|
||||
{!userSession && <h3>Please sign in</h3>}
|
||||
{showComponent && (
|
||||
<BugzillaComponentDetails
|
||||
{...showComponent}
|
||||
title={showComponent.title}
|
||||
onGoBack={this.handleComponentBackToMenu}
|
||||
/>
|
||||
{componentDetails && (
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<BugzillaComponentDetails
|
||||
{...componentDetails}
|
||||
onGoBack={this.handleComponentBackToMenu}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
{showPerson && (
|
||||
<PersonDetails
|
||||
person={showPerson}
|
||||
bugzillaComponents={Object.values(bugzillaComponents)}
|
||||
onGoBack={this.handleComponentBackToMenu}
|
||||
/>
|
||||
)}
|
||||
{!showComponent && !showPerson && partialOrg && userSession && (
|
||||
<MainView
|
||||
ldapEmail={ldapEmail}
|
||||
partialOrg={partialOrg}
|
||||
bugzillaComponents={Object.values(bugzillaComponents)}
|
||||
teamComponents={Object.values(teamComponents)}
|
||||
onComponentDetails={this.handleShowComponentDetails}
|
||||
onPersonDetails={this.handleShowPersonDetails}
|
||||
selectedTabIndex={selectedTabIndex}
|
||||
/>
|
||||
{personDetails && (
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<PersonDetails
|
||||
person={personDetails}
|
||||
bugzillaComponents={Object.values(bugzillaComponents)}
|
||||
onGoBack={this.handleComponentBackToMenu}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Switch>
|
||||
{partialOrg && (
|
||||
<PropsRoute
|
||||
path="/reportees"
|
||||
component={Reportees}
|
||||
ldapEmail={ldapEmail}
|
||||
partialOrg={partialOrg}
|
||||
onPersonDetails={this.handleShowPersonDetails}
|
||||
/>
|
||||
)}
|
||||
{partialOrg && (
|
||||
<PropsRoute
|
||||
path="/components"
|
||||
component={BugzillaComponents}
|
||||
bugzillaComponents={Object.values(bugzillaComponents)}
|
||||
onComponentDetails={this.handleShowComponentDetails}
|
||||
/>
|
||||
)}
|
||||
<PropsRoute
|
||||
path="/teams"
|
||||
component={BugzillaComponents}
|
||||
bugzillaComponents={Object.values(teamComponents)}
|
||||
onComponentDetails={this.handleShowComponentDetails}
|
||||
/>
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import BugzillaComponents from '../../src/components/BugzillaComponents';
|
||||
import bugzillaComponents from '../mocks/bugzillaComponents';
|
||||
import teamsConfig from '../../src/teamsConfig';
|
||||
|
||||
it('renders components', () => {
|
||||
const tree = renderer
|
||||
.create((
|
||||
<BugzillaComponents
|
||||
bugzillaComponents={bugzillaComponents}
|
||||
onComponentDetails={() => null}
|
||||
/>
|
||||
))
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders components bucketed as teams', () => {
|
||||
const tree = renderer
|
||||
.create((
|
||||
<BugzillaComponents
|
||||
bugzillaComponents={Object.values(teamsConfig)}
|
||||
onComponentDetails={() => null}
|
||||
/>
|
||||
))
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import Header from '../../src/components/Header';
|
||||
|
||||
it('renders the reportees tab', () => {
|
||||
const tree = renderer
|
||||
.create((
|
||||
<Router>
|
||||
<Header
|
||||
selectedTabIndex={0}
|
||||
handleTabChange={() => null}
|
||||
/>
|
||||
</Router>
|
||||
))
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
|
@ -1,57 +0,0 @@
|
|||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import MainView from '../../src/components/MainView';
|
||||
import partialOrg from '../mocks/partialOrg';
|
||||
import bugzillaComponents from '../mocks/bugzillaComponents';
|
||||
import teamsConfig from '../../src/teamsConfig';
|
||||
|
||||
it('renders Someone with no reportees', () => {
|
||||
const tree = renderer
|
||||
.create((
|
||||
<MainView
|
||||
ldapEmail="someone@mozilla.com"
|
||||
partialOrg={partialOrg}
|
||||
bugzillaComponents={bugzillaComponents}
|
||||
teams={{}}
|
||||
onComponentDetails={() => null}
|
||||
onPersonDetails={() => null}
|
||||
selectedTabIndex={0}
|
||||
/>
|
||||
))
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders Manager who has reportees', () => {
|
||||
const tree = renderer
|
||||
.create((
|
||||
<MainView
|
||||
ldapEmail="manager@mozilla.com"
|
||||
partialOrg={partialOrg}
|
||||
bugzillaComponents={bugzillaComponents}
|
||||
teams={{}}
|
||||
onComponentDetails={() => null}
|
||||
onPersonDetails={() => null}
|
||||
selectedTabIndex={0}
|
||||
/>
|
||||
))
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders Manager who has reportees and teams', () => {
|
||||
const tree = renderer
|
||||
.create((
|
||||
<MainView
|
||||
ldapEmail="manager@mozilla.com"
|
||||
partialOrg={partialOrg}
|
||||
bugzillaComponents={bugzillaComponents}
|
||||
teams={Object.values(teamsConfig)}
|
||||
onComponentDetails={() => null}
|
||||
onPersonDetails={() => null}
|
||||
selectedTabIndex={0}
|
||||
/>
|
||||
))
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import Reportees from '../../src/components/Reportees';
|
||||
import partialOrg from '../mocks/partialOrg';
|
||||
|
||||
it('renders Someone with no reportees', () => {
|
||||
const tree = renderer
|
||||
.create((
|
||||
<Reportees
|
||||
ldapEmail="someone@mozilla.com"
|
||||
partialOrg={partialOrg}
|
||||
onPersonDetails={() => null}
|
||||
/>
|
||||
))
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders Manager who has reportees', () => {
|
||||
const tree = renderer
|
||||
.create((
|
||||
<Reportees
|
||||
ldapEmail="manager@mozilla.com"
|
||||
partialOrg={partialOrg}
|
||||
onPersonDetails={() => null}
|
||||
/>
|
||||
))
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
|
@ -0,0 +1,293 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders components 1`] = `
|
||||
<div>
|
||||
<h3
|
||||
className="BugzillaComponents-header-1"
|
||||
/>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th />
|
||||
<th />
|
||||
<th
|
||||
className="BugzillaComponents-metricLabel-3"
|
||||
>
|
||||
Untriaged
|
||||
</th>
|
||||
<th
|
||||
className="BugzillaComponents-metricLabel-3"
|
||||
>
|
||||
Needinfo
|
||||
</th>
|
||||
<th
|
||||
className="BugzillaComponents-metricLabel-3"
|
||||
>
|
||||
P1s
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-4"
|
||||
name="Core::DOM: IndexedDB"
|
||||
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: IndexedDB
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-4"
|
||||
name="Core::JavaScript Engine"
|
||||
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::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>
|
||||
<td
|
||||
className="BugzillaComponents-metric-2"
|
||||
>
|
||||
<a
|
||||
href="https://bugzilla.mozilla.org/buglist.cgi?component=DOM%3A%20Core%20%26%20HTML&f1=bug_severity&f2=keywords&f3=resolution&limit=0&o1=notequals&o2=notsubstring&o3=isempty&product=Core&v1=enhancement&v2=meta"
|
||||
>
|
||||
944
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-4"
|
||||
name="Toolkit::Async Tooling"
|
||||
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>
|
||||
Toolkit::Async Tooling
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components bucketed as teams 1`] = `
|
||||
<div>
|
||||
<h3
|
||||
className="BugzillaComponents-header-1"
|
||||
/>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th />
|
||||
<th />
|
||||
<th
|
||||
className="BugzillaComponents-metricLabel-3"
|
||||
>
|
||||
Untriaged
|
||||
</th>
|
||||
<th
|
||||
className="BugzillaComponents-metricLabel-3"
|
||||
>
|
||||
Needinfo
|
||||
</th>
|
||||
<th
|
||||
className="BugzillaComponents-metricLabel-3"
|
||||
>
|
||||
P1s
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-4"
|
||||
name="DOM Core"
|
||||
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>
|
||||
DOM Core
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-4"
|
||||
name="DOM Fission"
|
||||
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>
|
||||
DOM Fission
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-4"
|
||||
name="Worker and Storage"
|
||||
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>
|
||||
Worker and Storage
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,182 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders the reportees tab 1`] = `
|
||||
<header
|
||||
className="MuiPaper-root-11 MuiPaper-elevation4-17 MuiAppBar-root-2 MuiAppBar-positionStatic-6 MuiAppBar-colorPrimary-9"
|
||||
>
|
||||
<div
|
||||
className="MuiToolbar-root-38 MuiToolbar-regular-40 MuiToolbar-gutters-39 Header-styledToolbar-1"
|
||||
>
|
||||
<div
|
||||
className="MuiTabs-root-42"
|
||||
>
|
||||
<div
|
||||
className="MuiTabs-flexContainer-43"
|
||||
>
|
||||
<div
|
||||
className="MuiTabs-scroller-45 MuiTabs-fixed-46"
|
||||
onScroll={[Function]}
|
||||
role="tablist"
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="MuiTabs-flexContainer-43"
|
||||
>
|
||||
<a
|
||||
aria-current={null}
|
||||
aria-selected={true}
|
||||
className="MuiButtonBase-root-63 MuiTab-root-51 MuiTab-textColorInherit-53 MuiTab-selected-56"
|
||||
href="/reportees"
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onContextMenu={[Function]}
|
||||
onFocus={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="tab"
|
||||
tabIndex="0"
|
||||
>
|
||||
<span
|
||||
className="MuiTab-wrapper-59"
|
||||
>
|
||||
<span
|
||||
className="MuiTab-labelContainer-60"
|
||||
>
|
||||
<span
|
||||
className="MuiTab-label-61"
|
||||
>
|
||||
Reportees
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="MuiTouchRipple-root-96"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
aria-current={null}
|
||||
aria-selected={false}
|
||||
className="MuiButtonBase-root-63 MuiTab-root-51 MuiTab-textColorInherit-53"
|
||||
href="/teams"
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onContextMenu={[Function]}
|
||||
onFocus={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="tab"
|
||||
tabIndex="0"
|
||||
>
|
||||
<span
|
||||
className="MuiTab-wrapper-59"
|
||||
>
|
||||
<span
|
||||
className="MuiTab-labelContainer-60"
|
||||
>
|
||||
<span
|
||||
className="MuiTab-label-61"
|
||||
>
|
||||
Teams
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="MuiTouchRipple-root-96"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
aria-current={null}
|
||||
aria-selected={false}
|
||||
className="MuiButtonBase-root-63 MuiTab-root-51 MuiTab-textColorInherit-53"
|
||||
href="/components"
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onContextMenu={[Function]}
|
||||
onFocus={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="tab"
|
||||
tabIndex="0"
|
||||
>
|
||||
<span
|
||||
className="MuiTab-wrapper-59"
|
||||
>
|
||||
<span
|
||||
className="MuiTab-labelContainer-60"
|
||||
>
|
||||
<span
|
||||
className="MuiTab-label-61"
|
||||
>
|
||||
Components
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="MuiTouchRipple-root-96"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<span
|
||||
className="MuiPrivateTabIndicator-root-66 MuiPrivateTabIndicator-colorSecondary-68 MuiTabs-indicator-50"
|
||||
style={
|
||||
Object {
|
||||
"left": 0,
|
||||
"width": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="MuiButtonBase-root-63 MuiButton-root-70 MuiButton-contained-81 MuiButton-containedSecondary-83 MuiButton-raised-84 MuiButton-raisedSecondary-86 MuiButton-sizeSmall-93 CredentialsMenu-button-69"
|
||||
disabled={false}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onContextMenu={[Function]}
|
||||
onFocus={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
tabIndex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="MuiButton-label-71"
|
||||
>
|
||||
Sign in
|
||||
</span>
|
||||
<span
|
||||
className="MuiTouchRipple-root-96"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
`;
|
|
@ -74,80 +74,6 @@ exports[`renders Manager who has reportees 1`] = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders Manager who has reportees and teams 1`] = `
|
||||
<div
|
||||
className="Reportees-root-1"
|
||||
>
|
||||
<div
|
||||
height="1rem"
|
||||
>
|
||||
|
||||
</div>
|
||||
<div
|
||||
className="Reportees-person-4"
|
||||
>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-5"
|
||||
name="manager@mozilla.com"
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="MuiSvgIcon-root-7 DrilldownIcon-icon-6"
|
||||
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>
|
||||
<span>
|
||||
Manager
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="Reportees-person-4"
|
||||
>
|
||||
<div
|
||||
className="DrilldownIcon-svgWrapper-5"
|
||||
name="someone@mozilla.com"
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="MuiSvgIcon-root-7 DrilldownIcon-icon-6"
|
||||
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>
|
||||
<span>
|
||||
Someone
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders Someone with no reportees 1`] = `
|
||||
<div
|
||||
className="Reportees-root-1"
|
Загрузка…
Ссылка в новой задаче