move components

This commit is contained in:
Iuri Matias 2019-11-06 16:15:25 -05:00
parent 2018d77045
commit dfc2df4db3
13 changed files with 271 additions and 191 deletions

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ yarn-debug.log*
yarn-error.log* yarn-error.log*
TODO TODO
src/logs/

24
log_script.js Normal file
View File

@ -0,0 +1,24 @@
const lineByLine = require('n-readlines');
const fs = require('fs-extra');
const liner = new lineByLine('./raw_logs.json');
let DB = {};
let line;
while (_line = liner.next()) {
if (_line.length === 0) continue;
let line = _line.toString('ascii')
let data = JSON.parse(line)
let id = data.id
if (DB[id]) {
DB[id] = {...DB[id], ...data}
continue;
}
DB[id] = data
}
console.dir("wrote " + Object.keys(DB).length + " keys");
fs.writeJSONSync("./log.json", DB);
console.dir("done");

View File

@ -9,7 +9,9 @@
"ansi-to-html": "^0.6.12", "ansi-to-html": "^0.6.12",
"autoscroll-react": "^3.2.0", "autoscroll-react": "^3.2.0",
"bootstrap": "^4.3.1", "bootstrap": "^4.3.1",
"fs-extra": "^8.1.0",
"jquery": "^3.4.1", "jquery": "^3.4.1",
"n-readlines": "^1.0.0",
"react": "^16.11.0", "react": "^16.11.0",
"react-bootstrap": "^1.0.0-beta.14", "react-bootstrap": "^1.0.0-beta.14",
"react-bootstrap-slider": "^2.2.2", "react-bootstrap-slider": "^2.2.2",

View File

@ -1,18 +1,13 @@
import React, {useState} from 'react'; import React from 'react';
import { SearchState, SortingState, IntegratedSorting, TreeDataState, CustomTreeData, FilteringState, IntegratedFiltering, TableColumnVisibility, DataTypeProvider } from '@devexpress/dx-react-grid';
import { Grid, Table, TableHeaderRow, TableTreeColumn, TableFilterRow, SearchPanel, Toolbar, ColumnChooser, TableColumnResizing, DragDropProvider, TableColumnReordering } from '@devexpress/dx-react-grid-bootstrap4';
import Convert from 'ansi-to-html';
import stripAnsi from 'strip-ansi';
import ReactJson from 'react-json-view';
import './App.css'; import './App.css';
import Logs from './Logs.js'; import DetailModal from './DetailModal.js';
import {Button, Card, Collapse, Navbar, Nav, Container, Modal} from 'react-bootstrap'; import ObjectSection from './ObjectSection.js';
import ReactBootstrapSlider from 'react-bootstrap-slider'; import ConsoleSection from './ConsoleSection.js';
import LogsSection from './LogsSection.js';
import all_data from './log_embark_run.json' import DebugBar from './DebugBar.js';
let convert = new Convert();
// import all_data from './logs/log_embark_run.json'
import all_data from './logs/log.json'
let all_data_ordered = Object.values(all_data).sort((x) => x.timestamp) let all_data_ordered = Object.values(all_data).sort((x) => x.timestamp)
let session_object = Object.values(all_data).find((x) => x.session === x.id) let session_object = Object.values(all_data).find((x) => x.session === x.id)
@ -20,116 +15,6 @@ let session_object = Object.values(all_data).find((x) => x.session === x.id)
let data = [session_object]; let data = [session_object];
const ImportFromFileBodyComponent = () => {
let fileReader;
const handleFileRead = (e) => {
const content = fileReader.result;
console.log(content);
// … do something with the 'content' …
};
const handleFileChosen = (file) => {
if (!file) return;
fileReader = new FileReader();
fileReader.onloadend = handleFileRead;
fileReader.readAsText(file);
};
return <div className='upload-expense'>
<input type='file'
id='file'
className='input-file'
accept='.csv'
onChange={e => handleFileChosen(e.target.files[0])}
/>
</div>;
};
function DetailModal({show, setShow, title, content}) {
return (
<>
<Modal
size="xl"
show={show}
onHide={() => setShow(false)}
// dialogClassName="modal-90w"
aria-labelledby="example-custom-modal-styling-title"
>
<Modal.Header closeButton>
<Modal.Title id="example-custom-modal-styling-title">
{title}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<ReactJson src={content} theme="monokai" groupArraysAfterLength={10} name={false} collapsed={3} />
</Modal.Body>
</Modal>
</>
);
}
function Section({title, children, defaultOpen}) {
const [open, setOpen] = useState(defaultOpen);
return (
<>
<Card>
<Card.Header onClick={() => setOpen(!open)} style={{"cursor": "pointer"}}>
{title}
</Card.Header>
<Collapse in={open}>
<Card.Body>
{children}
</Card.Body>
</Collapse>
</Card>
</>
);
}
const LogFormatter = ({ onClick }) => {
return (props) => {
return (
<span onClick={onClick(props)}>
{stripAnsi(props.value)}
</span>
)
}
};
const LogTypeProvider = (props) => {
console.dir(props)
return (
<DataTypeProvider
formatterComponent={LogFormatter(props)}
{...props}
/>
)
}
const StepFormatter = ({onClick}) => {
return (props) => {
return (
<span onClick={onClick(props)}>
{stripAnsi(props.value)}
</span>
);
}
}
const StepTypeProvider = (props) => {
return (
<DataTypeProvider
formatterComponent={StepFormatter(props)}
{...props}
/>
)
}
class App extends React.PureComponent { class App extends React.PureComponent {
constructor(props) { constructor(props) {
@ -152,8 +37,8 @@ class App extends React.PureComponent {
// { name: 'inputs', title: 'Inputs' }, // { name: 'inputs', title: 'Inputs' },
{ name: 'msg', title: 'Error' }, { name: 'msg', title: 'Error' },
], ],
rows: [session_object], // rows: [session_object],
tableColumnExtensions: [{ columnName: 'name', width: 300, align: 'left' }], rows: data,
// defaultExpandedRowIds: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27] // defaultExpandedRowIds: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]
defaultExpandedRowIds: [], defaultExpandedRowIds: [],
defaultHiddenColumnNames: ['session', 'parent_id', 'id', 'error'], defaultHiddenColumnNames: ['session', 'parent_id', 'id', 'error'],
@ -173,14 +58,6 @@ class App extends React.PureComponent {
{ columnName: 'msg', width: 200 }, { columnName: 'msg', width: 200 },
], ],
defaultOrder: ['session', 'parent_id', 'id', 'step', 'name', 'type', 'timestamp', 'msg'], defaultOrder: ['session', 'parent_id', 'id', 'step', 'name', 'type', 'timestamp', 'msg'],
numberFilterOperations: [
'equal',
'notEqual',
'greaterThan',
'greaterThanOrEqual',
'lessThan',
'lessThanOrEqual',
],
shouldShowModal: false, shouldShowModal: false,
modalTitle: "", modalTitle: "",
modalContent: {} modalContent: {}
@ -243,6 +120,7 @@ class App extends React.PureComponent {
for (let i=0; i<diff; i++) { for (let i=0; i<diff; i++) {
let newItem = all_data_ordered[this.state.current_index - diff - 1] let newItem = all_data_ordered[this.state.current_index - diff - 1]
if (!newItem) break;
data.pop(); data.pop();
nextLogs.pop() nextLogs.pop()
newItem.step = this.state.current_index - diff - 1 newItem.step = this.state.current_index - diff - 1
@ -272,7 +150,7 @@ class App extends React.PureComponent {
let newItem = all_data_ordered[current_step] let newItem = all_data_ordered[current_step]
if (!newItem) break; if (!newItem) break;
if (newItem.type.indexOf("log_") === 0) { if (newItem.type && newItem.type.indexOf("log_") === 0) {
nextLogs.push(current_step + ". " + newItem.name) nextLogs.push(current_step + ". " + newItem.name)
} else { } else {
nextLogs.push("") // easier to slice it after... nextLogs.push("") // easier to slice it after...
@ -336,62 +214,21 @@ class App extends React.PureComponent {
return ( return (
<div> <div>
<DetailModal show={this.state.shouldShowModal} setShow={this.setShow} title={this.state.modalTitle} content={this.state.modalContent} /> <DetailModal show={this.state.shouldShowModal} setShow={this.setShow} title={this.state.modalTitle} content={this.state.modalContent} />
<Navbar fixed="top" style={{"background-color": "white", "border-bottom": "1px solid black"}}> <DebugBar currentStep={this.state.current_index} maxStep={this.state.max_index} currentId={this.state.current_index} goBack={this.previousLog} goForward={this.nextLog} changeStep={this.changeValue} goToStep={this.goToStep} />
{/* <ImportFromFileBodyComponent /> */}
<Button onClick={() => { this.setState({shouldShowModal: true})}}>show</Button>
<Navbar.Brand href="#">StructLog</Navbar.Brand>
<Nav className="mr-auto">
step: {this.state.current_index} / {this.state.max_index} id: {this.state.current_id}
</Nav>
< inline>
<button onClick={() => { this.goToStep(1) }}>First</button>
<button onClick={this.previousLog}>Previous</button>
<ReactBootstrapSlider min={0} max={this.state.max_index} change={this.changeValue} value={this.state.current_index} />
<button onClick={this.nextLog}>Next</button>
<button onClick={() => { this.goToStep(this.state.max_index) }}>Last</button>
</inline>
</Navbar>
<div style={{"margin-top": "55px"}}> <div style={{"margin-top": "55px"}}>
<Section title="Current" defaultOpen={true}> <ObjectSection log={this.state.current} open={true} />
<ReactJson src={this.state.current} theme="monokai" groupArraysAfterLength={5} name={false} collapsed={2} /> <ConsoleSection logs={this.state.logs} open={true} />
</Section> <LogsSection
<Section title="Console Output" defaultOpen={true}> open={true}
<Logs> rows={this.state.rows}
{this.state.logs.map((item, i) => { columns={this.state.columns}
return ( viewRow={this.viewRow}
<div key={`message-${i}`}> getChildRows={this.getChildRows}
<p dangerouslySetInnerHTML={{ __html: (convert.toHtml(item || "")) }} /> defaultColumnWidths={this.state.defaultColumnWidths}
</div>
);
})}
</Logs>
</Section>
<Section title="Logs" defaultOpen={true}>
<Grid rows={this.state.rows} columns={this.state.columns} >
<LogTypeProvider for={["name"]} onClick={this.viewRow} />
<StepTypeProvider for={["step"]} onClick={this.viewRow} availableFilterOperations={this.state.numberFilterOperations} />
<TreeDataState defaultExpandedRowIds={this.state.defaultExpandedRowIds} />
<CustomTreeData getChildRows={this.getChildRows} />
<FilteringState defaultFilters={[]} />
<SearchState defaultValue="" />
<IntegratedFiltering />
<SortingState defaultSorting={[{ columnName: 'Timestamp', direction: 'asc' }]} />
<IntegratedSorting />
<DragDropProvider />
<Table columnExtensions={this.state.tableColumnExtensions} />
<TableColumnResizing defaultColumnWidths={this.state.defaultColumnWidths} />
<TableHeaderRow showSortingControls />
<TableColumnVisibility
defaultHiddenColumnNames={this.state.defaultHiddenColumnNames} defaultHiddenColumnNames={this.state.defaultHiddenColumnNames}
defaultOrder={this.state.defaultOrder}
/> />
<TableColumnReordering defaultOrder={this.state.defaultOrder} />
<Toolbar />
<SearchPanel />
<TableFilterRow showFilterSelector={true} />
<TableTreeColumn for="name" />
<ColumnChooser />
</Grid>
</Section>
</div> </div>
</div> </div>
); );

25
src/ConsoleSection.js Normal file
View File

@ -0,0 +1,25 @@
import React from 'react';
import Convert from 'ansi-to-html';
import Section from './Section.js';
import Logs from './Logs.js';
let convert = new Convert();
function ConsoleSection({logs, open}) {
return (
<Section title="Console Output" defaultOpen={open}>
<Logs>
{logs.map((item, i) => {
return (
<div key={`message-${i}`}>
<p dangerouslySetInnerHTML={{ __html: (convert.toHtml(item || "")) }} />
</div>
);
})}
</Logs>
</Section>
);
}
export default ConsoleSection;

23
src/DebugBar.js Normal file
View File

@ -0,0 +1,23 @@
import React from 'react';
import {Navbar, Nav} from 'react-bootstrap';
import ReactBootstrapSlider from 'react-bootstrap-slider';
function DebugBar({currentStep, maxStep, currentId, goBack, goForward, changeStep, goToStep}) {
return (
<Navbar fixed="top" style={{ "background-color": "white", "border-bottom": "1px solid black" }}>
<Navbar.Brand href="#">StructLog</Navbar.Brand>
<Nav className="mr-auto">
step: {currentStep} / {maxStep} id: {currentId}
</Nav>
< inline>
<button onClick={() => { goToStep(1) }}>First</button>
<button onClick={goBack}>Previous</button>
<ReactBootstrapSlider min={0} max={maxStep} change={changeStep} value={currentStep} />
<button onClick={goForward}>Next</button>
<button onClick={() => { goToStep(maxStep) }}>Last</button>
</inline>
</Navbar>
);
}
export default DebugBar;

28
src/DetailModal.js Normal file
View File

@ -0,0 +1,28 @@
import React from 'react';
import {Modal} from 'react-bootstrap';
import ReactJson from 'react-json-view';
function DetailModal({show, setShow, title, content}) {
return (
<>
<Modal
size="xl"
show={show}
onHide={() => setShow(false)}
// dialogClassName="modal-90w"
aria-labelledby="example-custom-modal-styling-title"
>
<Modal.Header closeButton>
<Modal.Title id="example-custom-modal-styling-title">
{title}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<ReactJson src={content} theme="monokai" groupArraysAfterLength={10} name={false} collapsed={3} />
</Modal.Body>
</Modal>
</>
);
}
export default DetailModal;

49
src/Formatters.js Normal file
View File

@ -0,0 +1,49 @@
import React from 'react';
import { DataTypeProvider } from '@devexpress/dx-react-grid';
import stripAnsi from 'strip-ansi';
const LogFormatter = ({ onClick }) => {
return (props) => {
return (
<span onClick={onClick(props)}>
{stripAnsi(props.value)}
</span>
)
}
};
const LogTypeProvider = (props) => {
console.dir(props)
return (
<DataTypeProvider
formatterComponent={LogFormatter(props)}
{...props}
/>
)
}
const StepFormatter = ({onClick}) => {
return (props) => {
return (
<span onClick={onClick(props)}>
{stripAnsi(props.value)}
</span>
);
}
}
const StepTypeProvider = (props) => {
return (
<DataTypeProvider
formatterComponent={StepFormatter(props)}
{...props}
/>
)
}
export {
LogFormatter,
LogTypeProvider,
StepFormatter,
StepTypeProvider
}

49
src/LogsSection.js Normal file
View File

@ -0,0 +1,49 @@
import React from 'react';
import { SearchState, SortingState, IntegratedSorting, TreeDataState, CustomTreeData, FilteringState, IntegratedFiltering, TableColumnVisibility } from '@devexpress/dx-react-grid';
import { Grid, Table, TableHeaderRow, TableTreeColumn, TableFilterRow, SearchPanel, Toolbar, ColumnChooser, TableColumnResizing, DragDropProvider, TableColumnReordering } from '@devexpress/dx-react-grid-bootstrap4';
import {LogTypeProvider, StepTypeProvider} from './Formatters.js';
import Section from './Section.js';
let numberFilterOperations = [
'equal',
'notEqual',
'greaterThan',
'greaterThanOrEqual',
'lessThan',
'lessThanOrEqual',
];
let tableColumnExtensions = [{ columnName: 'name', width: 300, align: 'left' }];
function LogsSection({open, rows, columns, viewRow, getChildRows, defaultColumnWidths, defaultHiddenColumnNames, defaultOrder}) {
return (
<Section title="Logs" defaultOpen={open}>
<Grid rows={rows} columns={columns} >
<LogTypeProvider for={["name"]} onClick={viewRow} />
<StepTypeProvider for={["step"]} onClick={viewRow} availableFilterOperations={numberFilterOperations} />
<TreeDataState defaultExpandedRowIds={[]} />
<CustomTreeData getChildRows={getChildRows} />
<FilteringState defaultFilters={[]} />
<SearchState defaultValue="" />
<IntegratedFiltering />
<SortingState defaultSorting={[{ columnName: 'Timestamp', direction: 'asc' }]} />
<IntegratedSorting />
<DragDropProvider />
<Table columnExtensions={tableColumnExtensions} />
<TableColumnResizing defaultColumnWidths={defaultColumnWidths} />
<TableHeaderRow showSortingControls />
<TableColumnVisibility defaultHiddenColumnNames={defaultHiddenColumnNames} />
<TableColumnReordering defaultOrder={defaultOrder} />
<Toolbar />
<SearchPanel />
<TableFilterRow showFilterSelector={true} />
<TableTreeColumn for="name" />
<ColumnChooser />
</Grid>
</Section>
);
}
export default LogsSection;

14
src/ObjectSection.js Normal file
View File

@ -0,0 +1,14 @@
import React from 'react';
import ReactJson from 'react-json-view';
import Section from './Section.js';
function ObjectSection({log, open}) {
return (
<Section title="Current" defaultOpen={open}>
<ReactJson src={log} theme="monokai" groupArraysAfterLength={5} name={false} collapsed={2} />
</Section>
);
}
export default ObjectSection;

24
src/Section.js Normal file
View File

@ -0,0 +1,24 @@
import React, {useState} from 'react';
import {Card, Collapse} from 'react-bootstrap';
function Section({title, children, defaultOpen}) {
const [open, setOpen] = useState(defaultOpen);
return (
<>
<Card>
<Card.Header onClick={() => setOpen(!open)} style={{"cursor": "pointer"}}>
{title}
</Card.Header>
<Collapse in={open}>
<Card.Body>
{children}
</Card.Body>
</Collapse>
</Card>
</>
);
}
export default Section;

File diff suppressed because one or more lines are too long

View File

@ -6488,6 +6488,11 @@ mute-stream@0.0.7:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
n-readlines@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/n-readlines/-/n-readlines-1.0.0.tgz#c353797f216c253fdfef7e91da4e8b17c29a91a6"
integrity sha512-ISDqGcspVu6U3VKqtJZG1uR55SmNNF9uK0EMq1IvNVVZOui6MW6VR0+pIZhqz85ORAGp+4zW+5fJ/SE7bwEibA==
nan@^2.12.1: nan@^2.12.1:
version "2.14.0" version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"