Repository: aurora Updated Branches: refs/heads/master 94999eb75 -> e161c97ba
Add URL handling for tab switching on Job page Reviewed at https://reviews.apache.org/r/62958/ Project: http://git-wip-us.apache.org/repos/asf/aurora/repo Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/e161c97b Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/e161c97b Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/e161c97b Branch: refs/heads/master Commit: e161c97bab9927bc18fcc8bbc51b8ae2b76f1f4d Parents: 94999eb Author: David McLaughlin <[email protected]> Authored: Tue Oct 17 13:29:43 2017 -0700 Committer: David McLaughlin <[email protected]> Committed: Tue Oct 17 13:29:43 2017 -0700 ---------------------------------------------------------------------- ui/package.json | 1 + ui/src/main/js/components/Tabs.js | 13 ++++-- .../main/js/components/__tests__/Tabs-test.js | 6 +-- ui/src/main/js/pages/Job.js | 48 ++++++++++++++++---- ui/src/main/js/pages/__tests__/Job-test.js | 26 +++++++++-- 5 files changed, 75 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aurora/blob/e161c97b/ui/package.json ---------------------------------------------------------------------- diff --git a/ui/package.json b/ui/package.json index c7f593d..3895056 100644 --- a/ui/package.json +++ b/ui/package.json @@ -8,6 +8,7 @@ "diff": "^3.4.0", "es6-shim": "^0.35.3", "moment": "^2.18.1", + "query-string": "^5.0.0", "react": "^16.0.0", "react-dom": "^16.0.0", "react-router-dom": "^4.2.2" http://git-wip-us.apache.org/repos/asf/aurora/blob/e161c97b/ui/src/main/js/components/Tabs.js ---------------------------------------------------------------------- diff --git a/ui/src/main/js/components/Tabs.js b/ui/src/main/js/components/Tabs.js index 43b1950..e382aa7 100644 --- a/ui/src/main/js/components/Tabs.js +++ b/ui/src/main/js/components/Tabs.js @@ -8,24 +8,27 @@ export default class Tabs extends React.Component { constructor(props) { super(props); this.state = { - active: props.activeTab || props.tabs[0].name + active: props.activeTab || props.tabs[0].id }; } - select(name) { - this.setState({active: name}); + select(tab) { + this.setState({active: tab.id}); + if (this.props.onChange) { + this.props.onChange(tab); + } } render() { const that = this; - const isActive = (t) => t.name === that.state.active; + const isActive = (t) => t.id === that.state.active; return (<div className={addClass('tabs', this.props.className)}> <ul className='tab-navigation'> {this.props.tabs.map((t) => ( <li className={isActive(t) ? 'active' : ''} key={t.name} - onClick={(e) => this.select(t.name)}> + onClick={(e) => this.select(t)}> {t.icon ? <Icon name={t.icon} /> : ''} {t.name} </li>))} http://git-wip-us.apache.org/repos/asf/aurora/blob/e161c97b/ui/src/main/js/components/__tests__/Tabs-test.js ---------------------------------------------------------------------- diff --git a/ui/src/main/js/components/__tests__/Tabs-test.js b/ui/src/main/js/components/__tests__/Tabs-test.js index e028c2d..252e5e0 100644 --- a/ui/src/main/js/components/__tests__/Tabs-test.js +++ b/ui/src/main/js/components/__tests__/Tabs-test.js @@ -6,9 +6,9 @@ import Tabs from '../Tabs'; const DummyTab = ({ number }) => <span>Hello, {number}</span>; const tabs = [ - {name: 'one', content: <DummyTab number={1} />}, - {name: 'two', content: <DummyTab number={2} />}, - {name: 'three', content: <DummyTab number={3} />} + {id: 'one', name: 'one', content: <DummyTab number={1} />}, + {id: 'two', name: 'two', content: <DummyTab number={2} />}, + {id: 'three', name: 'three', content: <DummyTab number={3} />} ]; describe('Tabs', () => { http://git-wip-us.apache.org/repos/asf/aurora/blob/e161c97b/ui/src/main/js/pages/Job.js ---------------------------------------------------------------------- diff --git a/ui/src/main/js/pages/Job.js b/ui/src/main/js/pages/Job.js index fc400f7..5f92ad0 100644 --- a/ui/src/main/js/pages/Job.js +++ b/ui/src/main/js/pages/Job.js @@ -1,4 +1,5 @@ import React from 'react'; +import queryString from 'query-string'; import Breadcrumb from 'components/Breadcrumb'; import JobConfig from 'components/JobConfig'; @@ -13,6 +14,11 @@ import { isNully, sort } from 'utils/Common'; import { getLastEventTime, isActive } from 'utils/Task'; import { isInProgressUpdate } from 'utils/Update'; +export const TASK_CONFIG_TAB = 'config'; +export const TASK_LIST_TAB = 'tasks'; +export const JOB_STATUS_TAB = 'status'; +export const JOB_HISTORY_TAB = 'history'; + export default class Job extends React.Component { constructor(props) { super(props); @@ -100,24 +106,46 @@ export default class Job extends React.Component { this.state.tasks.filter((t) => !isActive(t)), (t) => getLastEventTime(t), true); return { + id: JOB_HISTORY_TAB, name: `Job History (${terminalTasks.length})`, content: <PanelGroup><TaskList tasks={terminalTasks} /></PanelGroup> }; } + setJobView(tabId) { + const {match: {params: {role, environment, name}}} = this.props; + this.props.history.push(`/beta/scheduler/${role}/${environment}/${name}?jobView=${tabId}`); + } + + setTaskView(tabId) { + const {match: {params: {role, environment, name}}} = this.props; + this.props.history.push(`/beta/scheduler/${role}/${environment}/${name}?taskView=${tabId}`); + } + jobStatusTab() { const activeTasks = sort(this.state.tasks.filter(isActive), (t) => t.assignedTask.instanceId); const numberConfigs = isNully(this.state.configGroups) ? '' : this.state.configGroups.length; return { + id: JOB_STATUS_TAB, name: 'Job Status', content: (<PanelGroup> - <Tabs className='task-status-tabs' tabs={[ - {icon: 'th-list', name: 'Tasks', content: <TaskList tasks={activeTasks} />}, - { - icon: 'info-sign', - name: `Configuration (${numberConfigs})`, - content: <JobConfig groups={this.state.configGroups} /> - }]} /> + <Tabs + activeTab={queryString.parse(this.props.location.search).taskView} + className='task-status-tabs' + onChange={(t) => this.setTaskView(t.id)} + tabs={[ + { + icon: 'th-list', + id: TASK_LIST_TAB, + name: 'Tasks', + content: <TaskList tasks={activeTasks} /> + }, + { + icon: 'info-sign', + id: TASK_CONFIG_TAB, + name: `Configuration (${numberConfigs})`, + content: <JobConfig groups={this.state.configGroups} /> + }]} /> </PanelGroup>) }; } @@ -126,7 +154,11 @@ export default class Job extends React.Component { if (isNully(this.state.tasks)) { return <Loading />; } - return <Tabs className='job-overview' tabs={[this.jobStatusTab(), this.jobHistoryTab()]} />; + return <Tabs + activeTab={queryString.parse(this.props.location.search).jobView} + className='job-overview' + onChange={(t) => this.setJobView(t.id)} + tabs={[this.jobStatusTab(), this.jobHistoryTab()]} />; } render() { http://git-wip-us.apache.org/repos/asf/aurora/blob/e161c97b/ui/src/main/js/pages/__tests__/Job-test.js ---------------------------------------------------------------------- diff --git a/ui/src/main/js/pages/__tests__/Job-test.js b/ui/src/main/js/pages/__tests__/Job-test.js index 4cc76b8..2b126b6 100644 --- a/ui/src/main/js/pages/__tests__/Job-test.js +++ b/ui/src/main/js/pages/__tests__/Job-test.js @@ -27,10 +27,17 @@ function apiSpy() { }; } -describe('Update', () => { +describe('Job', () => { // basic props to force render of all components const props = (tasks = []) => { - return {api: apiSpy(), cluster: 'test', match: {params: params}, tasks: tasks}; + return { + api: apiSpy(), + cluster: 'test', + history: jest.fn(), + location: {}, + match: {params: params}, + tasks: tasks + }; }; it('Should render Loading and fire off calls for data', () => { @@ -41,7 +48,7 @@ describe('Update', () => { }); it('Should render breadcrumb with correct values', () => { - const el = shallow(<Job api={apiSpy()} cluster='test' match={{params: params}} tasks={[]} />); + const el = shallow(<Job {...props()} />); expect(el.contains(<Breadcrumb cluster='test' env={params.environment} @@ -98,4 +105,17 @@ describe('Update', () => { const taskList = el.find(Tabs).props().tabs[1].content.props.children; expect(taskList.props.tasks).toEqual([tasks[1]]); }); + + it('Should set default active tabs based on URL query parameters', () => { + const tasks = [ + ScheduledTaskBuilder.status(ScheduleStatus.PENDING).build(), + ScheduledTaskBuilder.status(ScheduleStatus.FINISHED).build() + ]; + const p = props(tasks); + p.location.search = '?taskView=config&jobView=history'; + const el = shallow(<Job {...p} />); + expect(el.find(Tabs).props().activeTab).toEqual('history'); + const nestedTab = el.find(Tabs).props().tabs[0].content.props.children.props.activeTab; + expect(nestedTab).toEqual('config'); + }); });
