Skip to content

Commit 4f207ed

Browse files
committed
Allow loading logs from local file
1 parent 8c08670 commit 4f207ed

File tree

6 files changed

+97
-12
lines changed

6 files changed

+97
-12
lines changed

js/App.js

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,48 @@ import ReactScrolla from 'react-scrolla';
44
import {LogProvider} from './Providers/LogProvider.js';
55
import {LogTable} from './Components/LogTable.js';
66
import {ToggleEntry} from './Components/ToggleEntry.js';
7-
import {App as AppContainer, SideBar, Content} from 'oc-react-components';
7+
import {LogUploader} from './Components/LogUploader.js';
8+
import {App as AppContainer, Entry, SideBar, Content, Separator} from 'oc-react-components';
89

910
import {LogSearch} from './Search.js';
11+
import {LogFile} from './Providers/LogFile.js'
1012

1113
import styles from '../css/app.css';
1214

1315
export class App extends Component {
1416
state = {
1517
'entries': [],
1618
'loading': false,
17-
'levels': [false, false, false, false, false]
19+
'levels': [false, false, false, false, false],
20+
provider: null
1821
};
1922

2023
constructor () {
2124
super();
2225
this.logProvider = new LogProvider(50);
2326
this.logProvider.on('entries', entries => {
24-
this.setState({entries});
27+
if (this.state.provider === this.logProvider) {
28+
this.setState({entries});
29+
}
2530
});
2631
OCA.Search.logreader = new LogSearch(this.logProvider);
2732
this.saveLevels = _.debounce(this.logProvider.setLevels, 100);
2833
}
2934

30-
async componentDidMount() {
35+
async componentDidMount () {
3136
const levels = await this.logProvider.getLevels();
32-
this.setState({levels});
37+
this.setState({levels, provider: this.logProvider});
3338
this.logProvider.load();
3439
}
3540

36-
fetchNextPage = async() => {
37-
this.setState({loading: true});
38-
this.logProvider.limit += 25;
39-
await this.logProvider.load();
40-
this.setState({loading: false});
41-
};
41+
fetchNextPage = _.throttle(async() => {
42+
if (this.state.provider.hasMore) {
43+
this.setState({loading: true});
44+
this.state.provider.limit += 25;
45+
await this.state.provider.load();
46+
this.setState({loading: false});
47+
}
48+
}, 100);
4249

4350
setLevel (level, newState) {
4451
let levels = this.state.levels;
@@ -53,6 +60,17 @@ export class App extends Component {
5360
this.saveLevels(levels);
5461
}
5562

63+
onLogFile = (content) => {
64+
const logFile = new LogFile(content);
65+
logFile.on('entries', entries => {
66+
if (this.state.provider === logFile) {
67+
this.setState({entries});
68+
}
69+
});
70+
this.setState({provider: logFile, entries: []});
71+
logFile.load();
72+
};
73+
5674
render () {
5775
let entries = this.state.entries.filter(entry=> {
5876
return this.state.levels[entry.level];
@@ -70,6 +88,8 @@ export class App extends Component {
7088
return (
7189
<AppContainer appId="logreader">
7290
<SideBar>
91+
<Entry><LogUploader onLogFile={this.onLogFile}/></Entry>
92+
<Separator/>
7393
{filters}
7494
</SideBar>
7595

js/Components/LogUploader.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {Component} from 'react/addons';
2+
import Dropzone from 'react-dropzone';
3+
4+
import style from './LogUploader.less';
5+
6+
export class LogUploader extends Component {
7+
state = {
8+
message: 'Load log file...'
9+
};
10+
11+
isLog (content) {
12+
return content[0] === '{' && content[content.length - 1] === '}';
13+
}
14+
15+
onDrop = (files) => {
16+
const file = files[0];
17+
const reader = new FileReader();
18+
reader.onload = (e) => {
19+
const content = e.target.result.trim();
20+
if (!this.isLog(content)) {
21+
this.setState({message: 'Invalid log file'});
22+
return;
23+
}
24+
this.props.onLogFile(content);
25+
};
26+
reader.readAsText(file);
27+
};
28+
29+
render () {
30+
const dropStyle = {
31+
margin: '0 -12px',
32+
padding: '0 12px'
33+
};
34+
return (
35+
<Dropzone style={dropStyle} onDrop={this.onDrop}>
36+
{this.state.message}
37+
</Dropzone>
38+
);
39+
}
40+
}

js/Components/LogUploader.less

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.logSelect {
2+
margin: 0 -12px;
3+
}

js/Providers/LogFile.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import {LogProvider} from './LogProvider.js'
2+
3+
export class LogFile extends LogProvider {
4+
constructor (content, limit) {
5+
super(limit);
6+
this.content = content;
7+
this.lines = this.content.split('\n');
8+
}
9+
10+
async loadEntries (offset, count = 50) {
11+
const start = this.lines.length - offset;
12+
const end = Math.max(start - count - 2, 0);
13+
const entries = this.lines.slice(end, start).reverse().map(JSON.parse)
14+
return {data: entries};
15+
}
16+
}

js/Providers/LogProvider.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import {EventEmitter} from 'events';
33
export class LogProvider extends EventEmitter {
44
static levels = ['Debug', 'Info', 'Warning', 'Error', 'Fatal'];
55

6+
fromFile = false;
67
cachedEntries = [];
8+
hasMore = true;
79

810
constructor (limit = 50) {
911
super();
@@ -37,10 +39,13 @@ export class LogProvider extends EventEmitter {
3739

3840
async load () {
3941
this.loading = true;
40-
if (this.cachedEntries.length >= this.limit) {
42+
if (this.cachedEntries.length >= this.limit || this.fromFile || !this.hasMore) {
4143
return;
4244
}
4345
var newData = await this.loadEntries(this.cachedEntries.length, this.limit - this.cachedEntries.length);
46+
if(newData.data.length === 0) {
47+
this.hasMore = false;
48+
}
4449
this.cachedEntries = this.cachedEntries.concat(newData.data);
4550
this.loading = false;
4651
this.emit('entries', this.cachedEntries);

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"less-loader": "^2.2.0",
6161
"oc-react-components": "^0.1.5",
6262
"react": "^0.13.3",
63+
"react-dropzone": "^2.1.0",
6364
"react-responsive": "0.0.8",
6465
"react-scrolla": "^0.1.0",
6566
"react-time": "^3.0.0"

0 commit comments

Comments
 (0)