Skip to content

Commit 4cd9cf0

Browse files
committed
allow toggling between absolute and relative dates
1 parent 8c1454e commit 4cd9cf0

File tree

7 files changed

+158
-33
lines changed

7 files changed

+158
-33
lines changed

appinfo/routes.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
1414
['name' => 'log#get', 'url' => '/get', 'verb' => 'GET'],
1515
['name' => 'log#search', 'url' => '/search', 'verb' => 'GET'],
16+
['name' => 'log#getSettings', 'url' => '/settings', 'verb' => 'GET'],
1617
['name' => 'log#getLevels', 'url' => '/levels', 'verb' => 'GET'],
1718
['name' => 'log#setLevels', 'url' => '/levels', 'verb' => 'PUT'],
19+
['name' => 'log#setRelative', 'url' => '/relative', 'verb' => 'PUT'],
1820
]];

controller/logcontroller.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ public function getLevels() {
8585
return new JSONResponse($this->config->getAppValue('logreader', 'levels', '11111'));
8686
}
8787

88+
public function getSettings() {
89+
return new JSONResponse([
90+
'levels' => $this->config->getAppValue('logreader', 'levels', '11111'),
91+
'dateformat' => $this->config->getSystemValue('logdateformat', \DateTime::ISO8601),
92+
'timezone' => $this->config->getSystemValue('logtimezone', 'UTC'),
93+
'relativedates' => (bool)$this->config->getAppValue('logreader', 'relativedates', true),
94+
]);
95+
}
96+
97+
/**
98+
* @param bool $relative
99+
*/
100+
public function setRelative($relative) {
101+
$this->config->setAppValue('logreader', 'relativedates', $relative);
102+
}
103+
88104
public function setLevels($levels) {
89105
$this->config->setAppValue('logreader', 'levels', $levels);
90106
}

js/App.js

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@ import {LogProvider} from './Providers/LogProvider.js';
55
import {LogTable} from './Components/LogTable.js';
66
import {ToggleEntry} from './Components/ToggleEntry.js';
77
import {LogUploader} from './Components/LogUploader.js';
8-
import {
9-
App as AppContainer,
10-
Entry,
11-
SideBar,
12-
Content,
13-
Separator
14-
} from 'oc-react-components';
8+
import {App as AppContainer, Entry, SideBar, Content, Separator, Settings} from 'oc-react-components';
159

1610
import {LogSearch} from './Search.js';
1711
import {LogFile} from './Providers/LogFile.js'
@@ -20,10 +14,12 @@ import styles from '../css/app.css';
2014

2115
export class App extends Component {
2216
state = {
23-
'entries': [],
24-
'loading': false,
25-
'levels': [false, false, false, false, false],
26-
provider: null
17+
entries: [],
18+
loading: false,
19+
levels: [false, false, false, false, false],
20+
provider: null,
21+
relative: true,
22+
dateFormat: 'Y-m-d\TH:i:sO'
2723
};
2824

2925
constructor () {
@@ -36,11 +32,19 @@ export class App extends Component {
3632
});
3733
OCA.Search.logreader = new LogSearch(this.logProvider);
3834
this.saveLevels = _.debounce(this.logProvider.setLevels, 100);
35+
this.saveRelative = _.debounce(this.logProvider.setRelative, 100);
3936
}
4037

4138
async componentDidMount () {
4239
const levels = await this.logProvider.getLevels();
43-
this.setState({levels, provider: this.logProvider});
40+
const relative = await this.logProvider.getRelative();
41+
const dateFormat = await this.logProvider.getDateFormat();
42+
this.setState({
43+
levels,
44+
relative,
45+
dateFormat,
46+
provider: this.logProvider
47+
});
4448
this.logProvider.load();
4549
}
4650

@@ -77,6 +81,11 @@ export class App extends Component {
7781
logFile.load();
7882
};
7983

84+
setRelative = (relative) => {
85+
this.setState({relative});
86+
this.saveRelative(relative);
87+
};
88+
8089
render () {
8190
let entries = this.state.entries.filter(entry=> {
8291
if (!entry.level && entry.level !== 0) {
@@ -95,11 +104,18 @@ export class App extends Component {
95104
});
96105

97106
return (
107+
98108
<AppContainer appId="logreader">
99109
<SideBar><LogUploader
100110
onLogFile={this.onLogFile}/>
101111
<Separator/>
102112
{filters}
113+
<Settings>
114+
<ToggleEntry key='relative' active={this.state.relative}
115+
onChange={this.setRelative}>
116+
Relative Dates
117+
</ToggleEntry>
118+
</Settings>
103119
</SideBar>
104120

105121
<ReactScrolla
@@ -108,7 +124,9 @@ export class App extends Component {
108124
onPercentage={this.fetchNextPage}
109125
isLoading={this.state.loading}>
110126
<div className={styles.content}>
111-
<LogTable entries={entries}/>
127+
<LogTable entries={entries}
128+
relative={this.state.relative}
129+
dateFormat={this.state.dateFormat}/>
112130
</div>
113131
</ReactScrolla>
114132
</AppContainer>

js/Components/LogTable.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,51 @@ import {LogEntry} from './LogEntry.js';
33
import {LogLevel} from './LogLevel.js';
44
import Timestamp from 'react-time';
55
import MediaQuery from 'react-responsive';
6+
import {convertDateFormat} from '../DateFormatConverter.js'
67

78
import style from './LogTable.less';
89

910
export class LogTable extends Component {
1011
render () {
11-
var rows = this.props.entries.map((entry, i) => {
12-
var time = new Date(entry.time);
12+
const timeClass = style.time + ((this.props.relative) ? (' ' + style.relative) : '');
13+
14+
const getTimeStamp = (entry) => {
15+
const time = new Date(entry.time);
16+
if (this.props.relative) {
17+
return <Timestamp value={time} relative/>
18+
} else {
19+
return <Timestamp value={time}
20+
format={convertDateFormat(this.props.dateFormat)}/>
21+
}
22+
};
23+
const rows = this.props.entries.map((entry, i) => {
1324
return (
1425
<tr className={style['level_' + entry.level]} key={i}>
1526
<td className={style.level}><LogLevel level={entry.level}/>
1627
</td>
1728
<td className={style.app}>{entry.app}</td>
1829
<td className={style.message}><LogEntry
1930
message={entry.message}/></td>
20-
<td className={style.time}><Timestamp value={time}
21-
relative/></td>
31+
<td className={timeClass}>{getTimeStamp(entry)}</td>
2232
</tr>
2333
)
2434
});
2535

26-
var smallRows = this.props.entries.map((entry, i) => {
27-
var time = new Date(entry.time);
36+
const smallRows = this.props.entries.map((entry, i) => {
2837
return (
29-
<div className={style['level_' + entry.level] + ' ' + style.row} key={i}>
30-
<div className={style.level + ' ' + style.column}><LogLevel level={entry.level}/>
38+
<div className={style['level_' + entry.level] + ' ' + style.row}
39+
key={i}>
40+
<div className={style.level + ' ' + style.column}><LogLevel
41+
level={entry.level}/>
3142
</div>
32-
<div className={style.app + ' ' + style.column}>{entry.app}</div>
43+
<div
44+
className={style.app + ' ' + style.column}>{entry.app}</div>
3345

34-
<div className={style.time + ' ' + style.column}><Timestamp value={time}
35-
relative/></div>
36-
<div className={style.message + ' ' + style.column}><LogEntry
37-
message={entry.message}/></div>
46+
<div
47+
className={timeClass + ' ' + style.column}>{getTimeStamp(entry)}</div>
48+
<div className={style.message + ' ' + style.column}>
49+
<LogEntry
50+
message={entry.message}/></div>
3851
</div>
3952
)
4053
});
@@ -48,7 +61,7 @@ export class LogTable extends Component {
4861
<th className={style.level}>Level</th>
4962
<th className={style.app}>App</th>
5063
<th className={style.message}>Message</th>
51-
<th className={style.time}>Time</th>
64+
<th className={timeClass}>Time</th>
5265
</tr>
5366
</thead>
5467
<tbody>

js/Components/LogTable.less

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
}
1616

1717
.time {
18-
width: 120px;
19-
text-align: right;
18+
width: 180px;
19+
}
20+
21+
.time.relative {
22+
width: 100px;
2023
}
2124

2225
.app {

js/DateFormatConverter.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* PHP => moment.js
3+
*
4+
* http://www.php.net/manual/en/function.date.php
5+
* http://momentjs.com/docs/#/displaying/format/
6+
* https://gist.github.com/NTICompass/9375143
7+
*/
8+
const formatMap = {
9+
d: 'DD',
10+
D: 'ddd',
11+
j: 'D',
12+
l: 'dddd',
13+
N: 'E',
14+
w: 'd',
15+
W: 'W',
16+
F: 'MMMM',
17+
m: 'MM',
18+
M: 'MMM',
19+
n: 'M',
20+
o: 'GGGG',
21+
Y: 'YYYY',
22+
y: 'YY',
23+
a: 'a',
24+
A: 'A',
25+
g: 'h',
26+
G: 'H',
27+
h: 'hh',
28+
H: 'HH',
29+
i: 'mm',
30+
s: 'ss',
31+
u: '[u]', // not sure if moment has this
32+
e: '[e]', // moment does not have this
33+
O: 'ZZ',
34+
P: 'Z',
35+
T: '\T', // deprecated in moment
36+
c: 'YYYY-MM-DD[T]HH:mm:ssZ',
37+
r: 'ddd, DD MMM YYYY HH:mm:ss ZZ',
38+
U: 'X'
39+
};
40+
const formatEx = /[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]/g;
41+
42+
export function convertDateFormat (format) {
43+
return format.replace(formatEx, (phpStr) => {
44+
return typeof formatMap[phpStr] === 'function' ? formatMap[phpStr]() : formatMap[phpStr];
45+
});
46+
}

js/Providers/LogProvider.js

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

6+
cachedSettings = null;
67
fromFile = false;
78
cachedEntries = [];
89
hasMore = true;
@@ -43,7 +44,7 @@ export class LogProvider extends EventEmitter {
4344
return;
4445
}
4546
var newData = await this.loadEntries(this.cachedEntries.length, this.limit - this.cachedEntries.length);
46-
if(newData.data.length === 0) {
47+
if (newData.data.length === 0) {
4748
this.hasMore = false;
4849
}
4950
this.cachedEntries = this.cachedEntries.concat(newData.data);
@@ -66,17 +67,43 @@ export class LogProvider extends EventEmitter {
6667
}
6768
}
6869

69-
async getLevels() {
70-
const levels = await $.get(OC.generateUrl('/apps/logreader/levels'));
70+
async getSettings () {
71+
if (this.cachedSettings) {
72+
return this.cachedSettings;
73+
}
74+
this.cachedSettings = await $.get(OC.generateUrl('/apps/logreader/settings'));
75+
return this.cachedSettings;
76+
}
77+
78+
async getLevels () {
79+
const {levels} = await this.getSettings();
7180
return levels.split('').map(level => level > 0);
7281
}
7382

74-
setLevels(levels) {
83+
setLevels (levels) {
7584
const levelsString = levels.map(level => level ? 1 : 0).join('');
7685
return $.ajax({
7786
type: 'PUT',
7887
url: OC.generateUrl('/apps/logreader/levels'),
7988
data: {levels: levelsString}
8089
});
8190
}
91+
92+
async getRelative () {
93+
const {relativedates} = await this.getSettings();
94+
return relativedates;
95+
}
96+
97+
async getDateFormat(){
98+
const {dateformat} = await this.getSettings();
99+
return dateformat;
100+
}
101+
102+
setRelative (relative) {
103+
return $.ajax({
104+
type: 'PUT',
105+
url: OC.generateUrl('/apps/logreader/relative'),
106+
data: {relative}
107+
});
108+
}
82109
}

0 commit comments

Comments
 (0)