Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 1492273 - Convert selectedJob to a React context #4041

Merged
merged 1 commit into from Sep 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 1 addition & 4 deletions ui/index.html
Expand Up @@ -17,10 +17,7 @@
</div>
</div>
</div>
<job-view
revision="revision"
selected-job="selectedJob"
/>
<job-view />
</div>

<th-notification-box></th-notification-box>
Expand Down
167 changes: 78 additions & 89 deletions ui/job-view/JobView.jsx
Expand Up @@ -5,17 +5,18 @@ import SplitPane from 'react-split-pane';

import treeherder from '../js/treeherder';
import { thEvents, thFavicons } from '../js/constants';
import { SelectedJob } from './context/SelectedJob';
import { PinnedJobs } from './context/PinnedJobs';
import { matchesDefaults } from '../helpers/filter';
import { getAllUrlParams, getRepo } from '../helpers/location';
import { deployedRevisionUrl } from '../helpers/url';
import { getRepo } from '../helpers/location';
import ClassificationTypeModel from '../models/classificationType';
import FilterModel from '../models/filter';
import RepositoryModel from '../models/repository';
import DetailsPanel from './details/DetailsPanel';
import PrimaryNavBar from './headerbars/PrimaryNavBar';
import ActiveFilters from './headerbars/ActiveFilters';
import UpdateAvailable from './headerbars/UpdateAvailable';
import DetailsPanel from './details/DetailsPanel';
import PushList from './pushes/PushList';
import KeyboardShortcuts from './KeyboardShortcuts';

Expand Down Expand Up @@ -47,25 +48,28 @@ class JobView extends React.Component {
this.$rootScope.filterModel = filterModel;
// Set the URL to updated parameter styles, if needed. Otherwise it's a no-op.
filterModel.push();
const hasSelectedJob = getAllUrlParams().has('selectedJob');

this.state = {
repoName: getRepo(),
user: { isLoggedIn: false, isStaff: false },
filterModel,
isFieldFilterVisible: false,
pushListPct: props.selectedJob ? 100 - DEFAULT_DETAILS_PCT : 100,
pushListPct: hasSelectedJob ? 100 - DEFAULT_DETAILS_PCT : 100,
serverChangedDelayed: false,
serverChanged: false,
repos: [],
currentRepo: new RepositoryModel({ is_try_repo: true }),
classificationTypes: [],
classificationMap: {},
hasSelectedJob,
jobsLoaded: false,
};
}

static getDerivedStateFromProps(props) {
static getDerivedStateFromProps(props, state) {
return {
...JobView.getSplitterDimensions(props),
...JobView.getSplitterDimensions(state.hasSelectedJob),
repoName: getRepo(),
};
}
Expand All @@ -77,7 +81,6 @@ class JobView extends React.Component {
this.updateDimensions = this.updateDimensions.bind(this);
this.setCurrentRepoTreeStatus = this.setCurrentRepoTreeStatus.bind(this);
this.handleUrlChanges = this.handleUrlChanges.bind(this);
this.selectFirstJob = this.selectFirstJob.bind(this);

RepositoryModel.getList().then((repos) => {
const currentRepo = repos.find(repo => repo.name === repoName) || this.state.currentRepo;
Expand All @@ -100,6 +103,10 @@ class JobView extends React.Component {
this.toggleFieldFilterVisible();
});

this.jobsLoadedUnlisten = this.$rootScope.$on(thEvents.jobsLoaded, () => {
this.setState({ jobsLoaded: true });
});

// Get the current Treeherder revision and poll to notify on updates.
this.fetchDeployedRevision().then((revision) => {
this.setState({ serverRev: revision });
Expand Down Expand Up @@ -129,14 +136,14 @@ class JobView extends React.Component {
}

componentWillUnmount() {
this.jobsLoadedUnlisten();
this.toggleFieldFilterVisibleUnlisten();
window.removeEventListener('resize', this.updateDimensions, false);
window.removeEventListener('hashchange', this.handleUrlChanges, false);
}

static getSplitterDimensions(props) {
const { selectedJob } = props;
const defaultPushListPct = selectedJob ? 100 - DEFAULT_DETAILS_PCT : 100;
static getSplitterDimensions(hasSelectedJob) {
const defaultPushListPct = hasSelectedJob ? 100 - DEFAULT_DETAILS_PCT : 100;
// calculate the height of the details panel to use if it has not been
// resized by the user.
const defaultDetailsHeight = defaultPushListPct < 100 ?
Expand All @@ -163,6 +170,7 @@ class JobView extends React.Component {
this.setState({
filterModel,
serverChanged: false,
hasSelectedJob: getAllUrlParams().has('selectedJob'),
});
}

Expand All @@ -181,7 +189,7 @@ class JobView extends React.Component {
}

updateDimensions() {
this.setState(JobView.getSplitterDimensions(this.props));
this.setState(JobView.getSplitterDimensions(this.state.hasSelectedJob));
}

handleSplitChange(latestSplitSize) {
Expand All @@ -190,27 +198,13 @@ class JobView extends React.Component {
});
}

selectFirstJob(jobs) {
const { selectedJob } = this.props;

if (!selectedJob) {
this.$rootScope.$emit(thEvents.jobClick, jobs[0]);
}
}

clearIfEligibleTarget(target) {
if (target.hasAttribute('data-job-clear-on-click')) {
this.$rootScope.$emit(thEvents.clearSelectedJob, target);
}
}

render() {
const { revision, selectedJob, $injector } = this.props;
const { revision, $injector } = this.props;
const {
user, isFieldFilterVisible, serverChangedDelayed,
defaultPushListPct, defaultDetailsHeight, latestSplitPct, serverChanged,
currentRepo, repoName, repos, classificationTypes, classificationMap,
filterModel,
filterModel, jobsLoaded, hasSelectedJob,
} = this.state;

// TODO: Move this to the constructor. We are hitting some issues where
Expand All @@ -224,10 +218,10 @@ class JobView extends React.Component {
// we resize. Therefore, we must calculate the new
// height of the DetailsPanel based on the current height of the PushList.
// Reported this upstream: https://github.com/tomkp/react-split-pane/issues/282
const pushListPct = latestSplitPct === undefined || !selectedJob ?
const pushListPct = latestSplitPct === undefined || !hasSelectedJob ?
defaultPushListPct :
latestSplitPct;
const detailsHeight = latestSplitPct === undefined || !selectedJob ?
const detailsHeight = latestSplitPct === undefined || !hasSelectedJob ?
defaultDetailsHeight :
getWindowHeight() * (1 - latestSplitPct / 100);
const filterBarFilters = Object.entries(filterModel.urlParams).reduce((acc, [field, value]) => (
Expand All @@ -236,69 +230,69 @@ class JobView extends React.Component {
), []);

return (
<PinnedJobs
notify={this.thNotify}
selectedJob={selectedJob}
selectFirstJob={this.selectFirstJob}
>
<KeyboardShortcuts
filterModel={filterModel}
selectedJob={selectedJob}
<PinnedJobs notify={this.thNotify}>
<SelectedJob
jobsLoaded={jobsLoaded}
notify={this.thNotify}
$injector={$injector}
>
<PrimaryNavBar
repos={repos}
updateButtonClick={this.updateButtonClick}
serverChanged={serverChanged}
<KeyboardShortcuts
filterModel={filterModel}
setUser={this.setUser}
user={user}
setCurrentRepoTreeStatus={this.setCurrentRepoTreeStatus}
$injector={$injector}
resultSetStore={this.ThResultSetStore}
/>
<SplitPane
split="horizontal"
size={`${pushListPct}%`}
onChange={size => this.handleSplitChange(size)}
>
<div className="d-flex flex-column w-100" onClick={evt => this.clearIfEligibleTarget(evt.target)}>
{(isFieldFilterVisible || !!filterBarFilters.length) && <ActiveFilters
$injector={$injector}
classificationTypes={classificationTypes}
filterModel={filterModel}
filterBarFilters={filterBarFilters}
isFieldFilterVisible={isFieldFilterVisible}
toggleFieldFilterVisible={this.toggleFieldFilterVisible}
/>}
{serverChangedDelayed && <UpdateAvailable
updateButtonClick={this.updateButtonClick}
/>}
<div id="th-global-content" className="th-global-content" data-job-clear-on-click>
<span className="th-view-content">
<PushList
user={user}
repoName={repoName}
revision={revision}
currentRepo={currentRepo}
filterModel={filterModel}
$injector={$injector}
/>
</span>
</div>
</div>
<DetailsPanel
resizedHeight={detailsHeight}
currentRepo={currentRepo}
repoName={repoName}
selectedJob={selectedJob}
<PrimaryNavBar
repos={repos}
updateButtonClick={this.updateButtonClick}
serverChanged={serverChanged}
filterModel={filterModel}
setUser={this.setUser}
user={user}
classificationTypes={classificationTypes}
classificationMap={classificationMap}
setCurrentRepoTreeStatus={this.setCurrentRepoTreeStatus}
resultSetStore={this.ThResultSetStore}
$injector={$injector}
/>
</SplitPane>
</KeyboardShortcuts>
<SplitPane
split="horizontal"
size={`${pushListPct}%`}
onChange={size => this.handleSplitChange(size)}
>
<div className="d-flex flex-column w-100">
{(isFieldFilterVisible || !!filterBarFilters.length) && <ActiveFilters
$injector={$injector}
classificationTypes={classificationTypes}
filterModel={filterModel}
filterBarFilters={filterBarFilters}
isFieldFilterVisible={isFieldFilterVisible}
toggleFieldFilterVisible={this.toggleFieldFilterVisible}
/>}
{serverChangedDelayed && <UpdateAvailable
updateButtonClick={this.updateButtonClick}
/>}
<div id="th-global-content" className="th-global-content" data-job-clear-on-click>
<span className="th-view-content">
<PushList
user={user}
repoName={repoName}
revision={revision}
currentRepo={currentRepo}
filterModel={filterModel}
$injector={$injector}
/>
</span>
</div>
</div>
<DetailsPanel
resizedHeight={detailsHeight}
currentRepo={currentRepo}
repoName={repoName}
user={user}
classificationTypes={classificationTypes}
classificationMap={classificationMap}
$injector={$injector}
/>
</SplitPane>
</KeyboardShortcuts>
</SelectedJob>
</PinnedJobs>
);
}
Expand All @@ -307,16 +301,11 @@ class JobView extends React.Component {
JobView.propTypes = {
$injector: PropTypes.object.isRequired,
revision: PropTypes.string,
selectedJob: PropTypes.object,
};

// Some of these props are not ready by the time this renders.
JobView.defaultProps = {
revision: null,
selectedJob: null,
};

treeherder.component('jobView', react2angular(
JobView,
['revision', 'selectedJob'],
['$injector']));
treeherder.component('jobView', react2angular(JobView, [], ['$injector']));