Leverage refactored API for displaying playbook details

Numbers for the summary are now provided, we no longer need to count them.

We no longer need dedicated task actions (for now), remove them.

In the playbook details, we now iterate through each play to print a table that reconciles
tasks, results and hosts involved in that play.

The design of the UI is not final and is mostly a proof of concept for
the visualizing the refactored API.

Depends-On: https://review.openstack.org/#/c/641136/
Change-Id: I27180fab04e1192516be6f12fee53c299f434fee
This commit is contained in:
David Moreau Simard 2019-03-18 17:32:12 -04:00
parent 6a927681fa
commit bb4685eb09
No known key found for this signature in database
GPG Key ID: CBEB466764A9E621
5 changed files with 74 additions and 79 deletions

View File

@ -7,6 +7,7 @@
"@patternfly/patternfly-next": "^1.0.175",
"@patternfly/react-icons": "^3.5.0",
"@patternfly/react-tokens": "^2.0.4",
"@patternfly/react-core": "^2.3.6",
"axios": "^0.18.0",
"braces": "^2.3.2",
"react": "^16.8.4",

View File

@ -1,9 +1,10 @@
import React, { Component } from "react";
import { List, ListItem } from '@patternfly/react-core';
import { connect } from "react-redux";
import { isEmpty } from "lodash";
import { LoadingContainer, Container404 } from "../containers";
import { getPlaybook } from "./playbooksActions";
import TasksContainer from "../tasks/TasksContainer";
export class PlaybookContainer extends Component {
state = {
@ -31,12 +32,73 @@ export class PlaybookContainer extends Component {
<div>
<div className="pf-c-card">
<div class="pf-c-card__header">
<h1 className="pf-c-title pf-m-lg">Tasks</h1>
<h1 className="pf-c-title pf-m-lg">Hosts</h1>
</div>
<div className="pf-c-card__body">
<TasksContainer playbook={playbook} />
<table class="pf-c-table pf-m-compact pf-m-grid-md" role="grid">
<thead>
<tr>
<th>Name</th>
<th>OK</th>
<th>CHANGED</th>
<th>FAILED</th>
<th>SKIPPED</th>
<th>UNREACHABLE</th>
</tr>
</thead>
<tbody>
{playbook.hosts.map(host => (
<tr key={host.id}>
<td data-label="Name">{host.name}</td>
<td data-label="OK">{host.ok}</td>
<td data-label="CHANGED">{host.changed}</td>
<td data-label="FAILED">{host.failed}</td>
<td data-label="SKIPPED">{host.skipped}</td>
<td data-label="UNREACHABLE">{host.unreachable}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="pf-c-card">
<div class="pf-c-card__header">
<h1 className="pf-c-title pf-m-lg">Plays</h1>
</div>
{playbook.plays.map(play => (
<div className="pf-c-card__body">
<h2>{play.name}</h2>
<List>
<ListItem>Started: {play.started}</ListItem>
<ListItem>Ended: {play.ended}</ListItem>
<ListItem>Duration: {play.duration}</ListItem>
</List>
<table class="pf-c-table pf-m-compact pf-m-grid-md" role="grid">
<thead>
<tr>
<th>Task</th>
<th>Host</th>
<th>Action</th>
<th>Duration</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{play.tasks.map(task =>
task.results.map(result =>
<tr key={result.id}>
<th data-label="Task">{task.name}</th>
<th data-label="Host">{result.host.name}</th>
<th data-label="Action">{task.action}</th>
<th data-label="Duration">{result.duration}</th>
<th data-label="Status">{result.status}</th>
</tr>
))}
</tbody>
</table>
</div>
))}
</div>
</div>
);
}

View File

@ -149,19 +149,22 @@ export default class Playbook extends Component {
</StatusAndName>
<PlaybookInfos>
<PlaybookInfo>
<b>{playbook.hosts.length}</b> Hosts
<b>{playbook.items.plays}</b> Plays
</PlaybookInfo>
<PlaybookInfo>
<b>{playbook.files.length}</b> Files
<b>{playbook.items.tasks}</b> Tasks
</PlaybookInfo>
<PlaybookInfo>
<b>{Object.keys(playbook.tasks).length}</b> tasks
<b>{playbook.items.results}</b> Results
</PlaybookInfo>
<PlaybookInfo>
<b>{Object.keys(playbook.plays).length}</b> plays
<b>{playbook.items.hosts}</b> Hosts
</PlaybookInfo>
<PlaybookInfo>
<b>{Object.keys(playbook.records).length}</b> records
<b>{playbook.items.files}</b> Files
</PlaybookInfo>
<PlaybookInfo>
<b>{playbook.items.records}</b> Records
</PlaybookInfo>
</PlaybookInfos>
<Duration>

View File

@ -1,62 +0,0 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import { isEmpty } from "lodash";
import { getTasks } from "./tasksActions";
export class TasksContainer extends Component {
state = {
isLoading: true,
tasks: []
};
componentDidMount() {
const { playbook, getTasks } = this.props;
getTasks(playbook)
.then(response => this.setState({ tasks: response.data.results }))
.catch(error => console.log(error))
.then(() => this.setState({ isLoading: false }));
}
render() {
const { isLoading, tasks } = this.state;
if (isLoading) {
return null;
}
if (!isLoading && isEmpty(tasks)) {
return <div>no tasks for this playbook</div>;
}
return (
<table class="pf-c-table pf-m-compact pf-m-grid-md" role="grid">
<thead>
<tr>
<th>Name</th>
<th>Action</th>
<th>Duration</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{tasks.map(task => (
<tr key={task.id}>
<th data-label="Task Name">{task.name}</th>
<th data-label="Action">{task.action}</th>
<th data-label="Duration">{task.duration}</th>
<th data-label="Status">{task.status}</th>
</tr>
))}
</tbody>
</table>
);
}
}
function mapDispatchToProps(dispatch) {
return {
getTasks: playbook => dispatch(getTasks(playbook))
};
}
export default connect(
null,
mapDispatchToProps
)(TasksContainer);

View File

@ -1,9 +0,0 @@
import axios from "axios";
export function getTasks(playbook) {
return (dispatch, getState) => {
const { apiURL } = getState().config;
return axios
.get(`${apiURL}/api/v1/tasks?playbook=${playbook.id}`);
};
}