1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-31 06:51:10 +03:00

WIP - react virtualizer

This commit is contained in:
Marliana Lara 2019-07-12 13:57:21 -04:00
parent 859c364fbe
commit da92889323
No known key found for this signature in database
GPG Key ID: 38C73B40DFA809EE
7 changed files with 220 additions and 30 deletions

View File

@ -4576,6 +4576,11 @@
}
}
},
"clsx": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.0.4.tgz",
"integrity": "sha512-1mQ557MIZTrL/140j+JVdRM6e31/OA4vTYxXgqIIZlndyfjHpyawKZia1Im05Vp9BWmImkcNrNtFYQMyFcgJDg=="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@ -5429,6 +5434,14 @@
"esutils": "^2.0.2"
}
},
"dom-helpers": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
"requires": {
"@babel/runtime": "^7.1.2"
}
},
"dom-serializer": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
@ -7174,7 +7187,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -7195,12 +7209,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -7215,17 +7231,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -7342,7 +7361,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -7354,6 +7374,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -7368,6 +7389,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -7375,12 +7397,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -7399,6 +7423,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -7479,7 +7504,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -7491,6 +7517,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -7576,7 +7603,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -7612,6 +7640,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -7631,6 +7660,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -7674,12 +7704,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},
@ -10790,6 +10822,11 @@
"type-check": "~0.3.2"
}
},
"linear-layout-vector": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/linear-layout-vector/-/linear-layout-vector-0.0.1.tgz",
"integrity": "sha1-OYEU1zA7bsx/1rJzr3uEAdi6nHA="
},
"load-json-file": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
@ -13130,8 +13167,7 @@
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
"dev": true
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-router": {
"version": "4.3.1",
@ -13190,6 +13226,20 @@
}
}
},
"react-virtualized": {
"version": "9.21.1",
"resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.21.1.tgz",
"integrity": "sha512-E53vFjRRMCyUTEKuDLuGH1ld/9TFzjf/fFW816PE4HFXWZorESbSTYtiZz1oAjra0MminaUU1EnvUxoGuEFFPA==",
"requires": {
"babel-runtime": "^6.26.0",
"clsx": "^1.0.1",
"dom-helpers": "^2.4.0 || ^3.0.0",
"linear-layout-vector": "0.0.1",
"loose-envify": "^1.3.0",
"prop-types": "^15.6.0",
"react-lifecycles-compat": "^3.0.4"
}
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",

View File

@ -70,6 +70,7 @@
"react-codemirror2": "^6.0.0",
"react-dom": "^16.4.1",
"react-router-dom": "^4.3.1",
"react-virtualized": "^9.21.1",
"styled-components": "^4.2.0"
}
}

View File

@ -18,6 +18,12 @@ class Jobs extends Base {
readDetail(id, type) {
return this.http.get(`/api/v2${BASE_URLS[type]}${id}/`);
}
readJobEvents(id, params = {}) {
return this.http.get(`${this.baseUrl}${id}/job_events/`, {
params,
});
}
}
export default Jobs;

View File

@ -1,31 +1,154 @@
import React, { Component } from 'react';
import { CardBody } from '@patternfly/react-core';
import MenuControls from './shared/MenuControls';
import styled from 'styled-components';
import { JobsAPI } from '@api';
import ContentError from '@components/ContentError';
import ContentLoading from '@components/ContentLoading';
import MenuControls from './shared/MenuControls';
import { List, AutoSizer } from 'react-virtualized';
const OutputToolbar = styled.div`
display: flex;
justify-content: space-between;
justify-content: flex-end;
`;
const OutputWrapper = styled.div`
height: calc(100vh - 325px);
background-color: #fafafa;
margin-top: 24px;
`;
const OutputRow = styled.div`
display: flex;
`;
class JobOutput extends Component {
listRef = React.createRef();
constructor(props) {
super(props);
this.state = {
contentError: null,
hasContentLoading: true,
results: [],
scrollToIndex: -1,
startIndex: 0,
stopIndex: 0,
};
this.loadJobEvents = this.loadJobEvents.bind(this);
this.renderRow = this.renderRow.bind(this);
this.handleScrollTop = this.handleScrollTop.bind(this);
this.handleScrollBottom = this.handleScrollBottom.bind(this);
this.handleScrollNext = this.handleScrollNext.bind(this);
this.handleScrollPrevious = this.handleScrollPrevious.bind(this);
}
componentDidMount() {
this.loadJobEvents();
}
async loadJobEvents() {
const { job } = this.props;
try {
const {
data: { results = [] },
} = await JobsAPI.readJobEvents(job.id);
this.setState({ results, hasContentLoading: true });
} catch (err) {
this.setState({ contentError: err });
} finally {
this.setState({ hasContentLoading: false });
}
}
renderRow({ index, key, style }) {
const { results } = this.state;
return (
<OutputRow key={key} style={style} className="row">
<div className="id">{results[index].id}</div>
<div className="content">{results[index].stdout}</div>
</OutputRow>
);
}
onRowsRendered = ({ startIndex, stopIndex }) => {
this.setState({ startIndex, stopIndex });
};
handleScrollPrevious() {
const { startIndex, stopIndex } = this.state;
const index = startIndex - (stopIndex - startIndex);
this.setState({ scrollToIndex: Math.max(0, index) });
}
handleScrollNext() {
const { stopIndex } = this.state;
this.setState({ scrollToIndex: stopIndex + 1});
}
handleScrollTop() {
this.setState({ scrollToIndex: 0 });
}
handleScrollBottom() {
const { results } = this.state;
this.setState({ scrollToIndex: results.length - 1 });
}
render() {
const { job } = this.props;
const {
results,
hasContentLoading,
contentError,
scrollToIndex,
startIndex,
stopIndex
} = this.state;
if (hasContentLoading) {
return <ContentLoading />;
}
if (contentError) {
return <ContentError error={contentError} />;
}
return (
<CardBody>
<b>{job.name}</b>
{/*Heading and Job Stats */}
{/*Host Status Bar */}
<OutputToolbar>
{/* Filter and Pagination */}
<b>Filter placeholder</b>
<MenuControls />
<MenuControls
onScrollTop={this.handleScrollTop}
onScrollBottom={this.handleScrollBottom}
onScrollNext={this.handleScrollNext}
onScrollPrevious={this.handleScrollPrevious}
/>
</OutputToolbar>
<ul>
<li>
</li>
</ul>
<OutputWrapper>
<AutoSizer>
{({ width, height }) => {
console.log('scroll to index', scrollToIndex);
console.log('start index', startIndex);
console.log('stop index', stopIndex);
return (
<List
ref={this.listRef}
width={width}
height={height}
rowHeight={50}
rowRenderer={this.renderRow}
rowCount={results.length}
overscanRowCount={5}
scrollToIndex={scrollToIndex}
onRowsRendered={this.onRowsRendered}
scrollToAlignment="start"
/>
);
}}
</AutoSizer>
</OutputWrapper>
</CardBody>
);
}

View File

@ -23,22 +23,32 @@ const Button = styled(PFButton)`
`;
class MenuControls extends Component {
constructor(props) {
super(props);
}
render() {
const {
onScrollTop,
onScrollBottom,
onScrollNext,
onScrollPrevious,
} = this.props;
return (
<Wrapper>
<Button variant="plain">
<PlusIcon />
</Button>
<Button variant="plain">
<Button onClick={onScrollPrevious} variant="plain">
<AngleUpIcon />
</Button>
<Button variant="plain">
<Button onClick={onScrollNext} variant="plain">
<AngleDownIcon />
</Button>
<Button variant="plain">
<Button onClick={onScrollTop} variant="plain">
<AngleDoubleUpIcon />
</Button>
<Button variant="plain">
<Button onClick={onScrollBottom} variant="plain">
<AngleDoubleDownIcon />
</Button>
</Wrapper>

View File

@ -15,7 +15,7 @@ const findChildren = () => {
AngleDoubleDownIcon = wrapper.find('AngleDoubleDownIcon');
AngleUpIcon = wrapper.find('AngleUpIcon');
AngleDownIcon = wrapper.find('AngleDownIcon');
}
};
describe('MenuControls', () => {
test('should render successfully', () => {

View File

@ -1 +1 @@
export { default as MenuControls } from './MenuControls';
export { default } from './MenuControls';