Add Search
This commit is contained in:
parent
09039778c2
commit
66998cafa8
5 changed files with 301 additions and 124 deletions
|
|
@ -119,6 +119,8 @@
|
||||||
cmd.push("--after=" + options.after);
|
cmd.push("--after=" + options.after);
|
||||||
if (options.merge)
|
if (options.merge)
|
||||||
cmd.push("-m");
|
cmd.push("-m");
|
||||||
|
if (options.grep)
|
||||||
|
cmd.push("--grep=" + options.grep);
|
||||||
|
|
||||||
/* journalctl doesn't allow reverse and follow together */
|
/* journalctl doesn't allow reverse and follow together */
|
||||||
if (options.reverse)
|
if (options.reverse)
|
||||||
|
|
|
||||||
316
src/player.jsx
316
src/player.jsx
|
|
@ -20,12 +20,53 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
let cockpit = require("cockpit");
|
let cockpit = require("cockpit");
|
||||||
let _ = cockpit.gettext;
|
let _ = cockpit.gettext;
|
||||||
|
let moment = require("moment");
|
||||||
let Term = require("term.js-cockpit");
|
let Term = require("term.js-cockpit");
|
||||||
let Journal = require("journal");
|
let Journal = require("journal");
|
||||||
let $ = require("jquery");
|
let $ = require("jquery");
|
||||||
require("console.css");
|
require("console.css");
|
||||||
require("bootstrap-slider");
|
require("bootstrap-slider");
|
||||||
|
|
||||||
|
let padInt = function (n, w) {
|
||||||
|
let i = Math.floor(n);
|
||||||
|
let a = Math.abs(i);
|
||||||
|
let s = a.toString();
|
||||||
|
for (w -= s.length; w > 0; w--) {
|
||||||
|
s = '0' + s;
|
||||||
|
}
|
||||||
|
return ((i < 0) ? '-' : '') + s;
|
||||||
|
};
|
||||||
|
|
||||||
|
let formatDateTime = function (ms) {
|
||||||
|
return moment(ms).format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format a time interval from a number of milliseconds.
|
||||||
|
*/
|
||||||
|
let formatDuration = function (ms) {
|
||||||
|
let v = Math.floor(ms / 1000);
|
||||||
|
let s = Math.floor(v % 60);
|
||||||
|
v = Math.floor(v / 60);
|
||||||
|
let m = Math.floor(v % 60);
|
||||||
|
v = Math.floor(v / 60);
|
||||||
|
let h = Math.floor(v % 24);
|
||||||
|
let d = Math.floor(v / 24);
|
||||||
|
let str = '';
|
||||||
|
|
||||||
|
if (d > 0) {
|
||||||
|
str += d + ' ' + _("days") + ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h > 0 || str.length > 0) {
|
||||||
|
str += padInt(h, 2) + ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
str += padInt(m, 2) + ':' + padInt(s, 2);
|
||||||
|
|
||||||
|
return (ms < 0 ? '-' : '') + str;
|
||||||
|
};
|
||||||
|
|
||||||
let scrollToBottom = function(id) {
|
let scrollToBottom = function(id) {
|
||||||
const el = document.getElementById(id);
|
const el = document.getElementById(id);
|
||||||
if (el) {
|
if (el) {
|
||||||
|
|
@ -564,6 +605,88 @@ class Slider extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SearchEntry(props) {
|
||||||
|
return (
|
||||||
|
<span className="search-result"><a onClick={(e) => props.fastForwardToTS(props.pos, e)}>{formatDuration(props.pos)}</a></span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Search extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.handleInputChange = this.handleInputChange.bind(this);
|
||||||
|
this.handleStream = this.handleStream.bind(this);
|
||||||
|
this.handleError = this.handleError.bind(this);
|
||||||
|
this.handleSearchSubmit = this.handleSearchSubmit.bind(this);
|
||||||
|
this.clearSearchResults = this.clearSearchResults.bind(this);
|
||||||
|
this.state = {
|
||||||
|
search: cockpit.location.options.search_rec || cockpit.location.options.search || "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInputChange(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const name = event.target.name;
|
||||||
|
const value = event.target.value;
|
||||||
|
let state = {};
|
||||||
|
state[name] = value;
|
||||||
|
this.setState(state);
|
||||||
|
cockpit.location.go(cockpit.location.path[0], $.extend(cockpit.location.options, {search_rec: value}));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSearchSubmit() {
|
||||||
|
this.journalctl = Journal.journalctl(
|
||||||
|
this.props.matchList,
|
||||||
|
{count: "all", follow: false, merge: true, grep: this.state.search});
|
||||||
|
this.journalctl.fail(this.handleError);
|
||||||
|
this.journalctl.stream(this.handleStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleStream(data) {
|
||||||
|
let items = data.map(item => {
|
||||||
|
return JSON.parse(item.MESSAGE);
|
||||||
|
});
|
||||||
|
items = items.map(item => {
|
||||||
|
return <SearchEntry key={item.id} fastForwardToTS={this.props.fastForwardToTS} pos={item.pos} />;
|
||||||
|
});
|
||||||
|
this.setState({items: items});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(data) {
|
||||||
|
this.props.errorService.addMessage(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSearchResults() {
|
||||||
|
delete cockpit.location.options.search;
|
||||||
|
cockpit.location.go(cockpit.location.path[0], cockpit.location.options);
|
||||||
|
this.setState({search: ""});
|
||||||
|
this.handleStream([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.state.search) {
|
||||||
|
this.handleSearchSubmit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="search-wrap">
|
||||||
|
<div className="input-group search-component">
|
||||||
|
<input type="text" className="form-control" name="search" value={this.state.search} onChange={this.handleInputChange} />
|
||||||
|
<span className="input-group-btn">
|
||||||
|
<button className="btn btn-default" onClick={this.handleSearchSubmit}><span className="glyphicon glyphicon-search" /></button>
|
||||||
|
<button className="btn btn-default" onClick={this.clearSearchResults}><span className="glyphicon glyphicon-remove" /></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="search-results">
|
||||||
|
{this.state.items}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class InputPlayer extends React.Component {
|
class InputPlayer extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const input = String(this.props.input).replace(/(?:\r\n|\r|\n)/g, " ");
|
const input = String(this.props.input).replace(/(?:\r\n|\r|\n)/g, " ");
|
||||||
|
|
@ -905,7 +1028,7 @@ export class Player extends React.Component {
|
||||||
|
|
||||||
handleKeyDown(event) {
|
handleKeyDown(event) {
|
||||||
let keyCodesFuncs = {
|
let keyCodesFuncs = {
|
||||||
"p": this.playPauseToggle,
|
"P": this.playPauseToggle,
|
||||||
"}": this.speedUp,
|
"}": this.speedUp,
|
||||||
"{": this.speedDown,
|
"{": this.speedDown,
|
||||||
"Backspace": this.speedReset,
|
"Backspace": this.speedReset,
|
||||||
|
|
@ -917,8 +1040,10 @@ export class Player extends React.Component {
|
||||||
"-": this.zoomOut,
|
"-": this.zoomOut,
|
||||||
"Z": this.fitIn,
|
"Z": this.fitIn,
|
||||||
};
|
};
|
||||||
if (keyCodesFuncs[event.key]) {
|
if (event.target.nodeName.toLowerCase() !== 'input') {
|
||||||
(keyCodesFuncs[event.key](event));
|
if (keyCodesFuncs[event.key]) {
|
||||||
|
(keyCodesFuncs[event.key](event));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1064,6 +1189,8 @@ export class Player extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let r = this.props.recording;
|
||||||
|
|
||||||
let speedExp = this.state.speedExp;
|
let speedExp = this.state.speedExp;
|
||||||
let speedFactor = Math.pow(2, Math.abs(speedExp));
|
let speedFactor = Math.pow(2, Math.abs(speedExp));
|
||||||
let speedStr;
|
let speedStr;
|
||||||
|
|
@ -1100,75 +1227,132 @@ export class Player extends React.Component {
|
||||||
|
|
||||||
// ensure react never reuses this div by keying it with the terminal widget
|
// ensure react never reuses this div by keying it with the terminal widget
|
||||||
return (
|
return (
|
||||||
<div id="recording-wrap">
|
<React.Fragment>
|
||||||
<div className="col-md-6 player-wrap">
|
<div className="row">
|
||||||
<div ref="wrapper" className="panel panel-default">
|
<div id="recording-wrap">
|
||||||
<div className="panel-heading">
|
<div className="col-md-6 player-wrap">
|
||||||
<span>{this.state.title}</span>
|
<div ref="wrapper" className="panel panel-default">
|
||||||
</div>
|
<div className="panel-heading">
|
||||||
<div className="panel-body">
|
<span>{this.state.title}</span>
|
||||||
<div className={(this.state.drag_pan ? "dragnpan" : "")} style={scrollwrap} ref="scrollwrap">
|
</div>
|
||||||
<div ref="term" className="console-ct" key={this.state.term} style={style} />
|
<div className="panel-body">
|
||||||
|
<div className={(this.state.drag_pan ? "dragnpan" : "")} style={scrollwrap} ref="scrollwrap">
|
||||||
|
<div ref="term" className="console-ct" key={this.state.term} style={style} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="panel-footer">
|
||||||
|
<Slider length={this.buf.pos} mark={this.state.currentTsPost} fastForwardFunc={this.fastForwardToTS} play={this.play} pause={this.pause} paused={this.state.paused} />
|
||||||
|
<button title="Play/Pause - Hotkey: p" type="button" ref="playbtn"
|
||||||
|
className="btn btn-default btn-lg margin-right-btn play-btn"
|
||||||
|
onClick={this.playPauseToggle}>
|
||||||
|
<i className={"fa fa-" + (this.state.paused ? "play" : "pause")}
|
||||||
|
aria-hidden="true" />
|
||||||
|
</button>
|
||||||
|
<button title="Skip Frame - Hotkey: ." type="button"
|
||||||
|
className="btn btn-default btn-lg margin-right-btn"
|
||||||
|
onClick={this.skipFrame}>
|
||||||
|
<i className="fa fa-step-forward" aria-hidden="true" />
|
||||||
|
</button>
|
||||||
|
<button title="Restart Playback - Hotkey: Shift-R" type="button"
|
||||||
|
className="btn btn-default btn-lg" onClick={this.rewindToStart}>
|
||||||
|
<i className="fa fa-fast-backward" aria-hidden="true" />
|
||||||
|
</button>
|
||||||
|
<button title="Fast-forward to end - Hotkey: Shift-G" type="button"
|
||||||
|
className="btn btn-default btn-lg margin-right-btn"
|
||||||
|
onClick={this.fastForwardToEnd}>
|
||||||
|
<i className="fa fa-fast-forward" aria-hidden="true" />
|
||||||
|
</button>
|
||||||
|
<button title="Speed /2 - Hotkey: {" type="button"
|
||||||
|
className="btn btn-default btn-lg" onClick={this.speedDown}>
|
||||||
|
/2
|
||||||
|
</button>
|
||||||
|
<button title="Reset Speed - Hotkey: Backspace" type="button"
|
||||||
|
className="btn btn-default btn-lg" onClick={this.speedReset}>
|
||||||
|
1:1
|
||||||
|
</button>
|
||||||
|
<button title="Speed x2 - Hotkey: }" type="button"
|
||||||
|
className="btn btn-default btn-lg margin-right-btn"
|
||||||
|
onClick={this.speedUp}>
|
||||||
|
x2
|
||||||
|
</button>
|
||||||
|
<span>{speedStr}</span>
|
||||||
|
<span style={to_right}>
|
||||||
|
<button title="Drag'n'Pan" type="button" className="btn btn-default btn-lg"
|
||||||
|
onClick={this.dragPan}>
|
||||||
|
<i className={"fa fa-" + (this.state.drag_pan ? "hand-rock-o" : "hand-paper-o")}
|
||||||
|
aria-hidden="true" /></button>
|
||||||
|
<button title="Zoom In - Hotkey: =" type="button" className="btn btn-default btn-lg"
|
||||||
|
onClick={this.zoomIn} disabled={this.state.term_zoom_max}>
|
||||||
|
<i className="fa fa-search-plus" aria-hidden="true" /></button>
|
||||||
|
<button title="Fit To - Hotkey: Z" type="button" className="btn btn-default btn-lg"
|
||||||
|
onClick={this.fitTo}><i className="fa fa-expand" aria-hidden="true" /></button>
|
||||||
|
<button title="Zoom Out - Hotkey: -" type="button" className="btn btn-default btn-lg"
|
||||||
|
onClick={this.zoomOut} disabled={this.state.term_zoom_min}>
|
||||||
|
<i className="fa fa-search-minus" aria-hidden="true" /></button>
|
||||||
|
</span>
|
||||||
|
<div id="input-player-wrap">
|
||||||
|
<InputPlayer input={this.state.input} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Search matchList={this.props.matchList} fastForwardToTS={this.fastForwardToTS} play={this.play} pause={this.pause} paused={this.state.paused} errorService={this.error_service} />
|
||||||
|
</div>
|
||||||
|
<div className="clearfix" />
|
||||||
|
<ErrorList list={this.error_service.errors} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="panel-footer">
|
</div>
|
||||||
<Slider length={this.buf.pos} mark={this.state.currentTsPost} fastForwardFunc={this.fastForwardToTS} play={this.play} pause={this.pause} paused={this.state.paused} />
|
<div className="col-md-6">
|
||||||
<button title={_("Play/Pause - Hotkey: p")} type="button" ref="playbtn"
|
<div className="panel panel-default">
|
||||||
className="btn btn-default btn-lg margin-right-btn play-btn"
|
<div className="panel-heading">
|
||||||
onClick={this.playPauseToggle}>
|
<span>{_("Recording")}</span>
|
||||||
<i className={"fa fa-" + (this.state.paused ? "play" : "pause")}
|
</div>
|
||||||
aria-hidden="true" />
|
<div className="panel-body">
|
||||||
</button>
|
<table className="form-table-ct">
|
||||||
<button title={_("Skip Frame - Hotkey: .")} type="button"
|
<tbody>
|
||||||
className="btn btn-default btn-lg margin-right-btn"
|
<tr>
|
||||||
onClick={this.skipFrame}>
|
<td>{_("ID")}</td>
|
||||||
<i className="fa fa-step-forward" aria-hidden="true" />
|
<td>{r.id}</td>
|
||||||
</button>
|
</tr>
|
||||||
<button title={_("Restart Playback - Hotkey: Shift-R")} type="button"
|
<tr>
|
||||||
className="btn btn-default btn-lg" onClick={this.rewindToStart}>
|
<td>{_("Hostname")}</td>
|
||||||
<i className="fa fa-fast-backward" aria-hidden="true" />
|
<td>{r.hostname}</td>
|
||||||
</button>
|
</tr>
|
||||||
<button title={_("Fast-forward to end - Hotkey: Shift-G")} type="button"
|
<tr>
|
||||||
className="btn btn-default btn-lg margin-right-btn"
|
<td>{_("Boot ID")}</td>
|
||||||
onClick={this.fastForwardToEnd}>
|
<td>{r.boot_id}</td>
|
||||||
<i className="fa fa-fast-forward" aria-hidden="true" />
|
</tr>
|
||||||
</button>
|
<tr>
|
||||||
<button title={_("Speed /2 - Hotkey: {")} type="button"
|
<td>{_("Session ID")}</td>
|
||||||
className="btn btn-default btn-lg" onClick={this.speedDown}>
|
<td>{r.session_id}</td>
|
||||||
/2
|
</tr>
|
||||||
</button>
|
<tr>
|
||||||
<button title={_("Reset Speed - Hotkey: Backspace")} type="button"
|
<td>{_("PID")}</td>
|
||||||
className="btn btn-default btn-lg" onClick={this.speedReset}>
|
<td>{r.pid}</td>
|
||||||
1:1
|
</tr>
|
||||||
</button>
|
<tr>
|
||||||
<button title={_("Speed x2 - Hotkey: }")} type="button"
|
<td>{_("Start")}</td>
|
||||||
className="btn btn-default btn-lg margin-right-btn"
|
<td>{formatDateTime(r.start)}</td>
|
||||||
onClick={this.speedUp}>
|
</tr>
|
||||||
x2
|
<tr>
|
||||||
</button>
|
<td>{_("End")}</td>
|
||||||
<span>{speedStr}</span>
|
<td>{formatDateTime(r.end)}</td>
|
||||||
<span style={to_right}>
|
</tr>
|
||||||
<button title={_("Drag'n'Pan")} type="button" className="btn btn-default btn-lg"
|
<tr>
|
||||||
onClick={this.dragPan}>
|
<td>{_("Duration")}</td>
|
||||||
<i className={"fa fa-" + (this.state.drag_pan ? "hand-rock-o" : "hand-paper-o")}
|
<td>{formatDuration(r.end - r.start)}</td>
|
||||||
aria-hidden="true" /></button>
|
</tr>
|
||||||
<button title={_("Zoom In - Hotkey: =")} type="button" className="btn btn-default btn-lg"
|
<tr>
|
||||||
onClick={this.zoomIn} disabled={this.state.term_zoom_max}>
|
<td>{_("User")}</td>
|
||||||
<i className="fa fa-search-plus" aria-hidden="true" /></button>
|
<td>{r.user}</td>
|
||||||
<button title={_("Fit To - Hotkey: Z")} type="button" className="btn btn-default btn-lg"
|
</tr>
|
||||||
onClick={this.fitTo}><i className="fa fa-expand" aria-hidden="true" /></button>
|
</tbody>
|
||||||
<button title={_("Zoom Out - Hotkey: -")} type="button" className="btn btn-default btn-lg"
|
</table>
|
||||||
onClick={this.zoomOut} disabled={this.state.term_zoom_min}>
|
|
||||||
<i className="fa fa-search-minus" aria-hidden="true" /></button>
|
|
||||||
</span>
|
|
||||||
<div id="input-player-wrap">
|
|
||||||
<InputPlayer input={this.state.input} />
|
|
||||||
</div>
|
</div>
|
||||||
<ErrorList list={this.error_service.errors} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -401,3 +401,24 @@ table.listing-ct > thead th:last-child, tr.listing-ct-item td:last-child {
|
||||||
.panel-footer {
|
.panel-footer {
|
||||||
padding: 5px 15px;
|
padding: 5px 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-result {
|
||||||
|
margin-left: 5px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results {
|
||||||
|
float: left;
|
||||||
|
min-height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-component {
|
||||||
|
float: left;
|
||||||
|
width: 33%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-wrap {
|
||||||
|
min-height: 25px;
|
||||||
|
display:block;
|
||||||
|
clear:both;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -404,6 +404,9 @@ class Recording extends React.Component {
|
||||||
|
|
||||||
goBackToList() {
|
goBackToList() {
|
||||||
if (cockpit.location.path[0]) {
|
if (cockpit.location.path[0]) {
|
||||||
|
if ("search_rec" in cockpit.location.options) {
|
||||||
|
delete cockpit.location.options.search_rec;
|
||||||
|
}
|
||||||
cockpit.location.go([], cockpit.location.options);
|
cockpit.location.go([], cockpit.location.options);
|
||||||
} else {
|
} else {
|
||||||
cockpit.location.go('/');
|
cockpit.location.go('/');
|
||||||
|
|
@ -420,7 +423,9 @@ class Recording extends React.Component {
|
||||||
ref="player"
|
ref="player"
|
||||||
matchList={this.props.recording.matchList}
|
matchList={this.props.recording.matchList}
|
||||||
logsTs={this.props.logsTs}
|
logsTs={this.props.logsTs}
|
||||||
onTsChange={this.props.onTsChange} />);
|
search={this.props.search}
|
||||||
|
onTsChange={this.props.onTsChange}
|
||||||
|
recording={r} />);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
|
|
@ -432,58 +437,7 @@ class Recording extends React.Component {
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="row">
|
{player}
|
||||||
{player}
|
|
||||||
<div className="col-md-6">
|
|
||||||
<div className="panel panel-default">
|
|
||||||
<div className="panel-heading">
|
|
||||||
<span>{_("Recording")}</span>
|
|
||||||
</div>
|
|
||||||
<div className="panel-body">
|
|
||||||
<table className="form-table-ct">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{_("ID")}</td>
|
|
||||||
<td>{r.id}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{_("Hostname")}</td>
|
|
||||||
<td>{r.hostname}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{_("Boot ID")}</td>
|
|
||||||
<td>{r.boot_id}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{_("Session ID")}</td>
|
|
||||||
<td>{r.session_id}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{_("PID")}</td>
|
|
||||||
<td>{r.pid}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{_("Start")}</td>
|
|
||||||
<td>{formatDateTime(r.start)}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{_("End")}</td>
|
|
||||||
<td>{formatDateTime(r.end)}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{_("Duration")}</td>
|
|
||||||
<td>{formatDuration(r.end - r.start)}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{_("User")}</td>
|
|
||||||
<td>{r.user}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -645,6 +599,7 @@ class View extends React.Component {
|
||||||
date_until: cockpit.location.options.date_until || "",
|
date_until: cockpit.location.options.date_until || "",
|
||||||
username: cockpit.location.options.username || "",
|
username: cockpit.location.options.username || "",
|
||||||
hostname: cockpit.location.options.hostname || "",
|
hostname: cockpit.location.options.hostname || "",
|
||||||
|
search: cockpit.location.options.search || "",
|
||||||
/* filter values end */
|
/* filter values end */
|
||||||
error_tlog_uid: false,
|
error_tlog_uid: false,
|
||||||
diff_hosts: false,
|
diff_hosts: false,
|
||||||
|
|
@ -671,6 +626,7 @@ class View extends React.Component {
|
||||||
date_until: cockpit.location.options.date_until || "",
|
date_until: cockpit.location.options.date_until || "",
|
||||||
username: cockpit.location.options.username || "",
|
username: cockpit.location.options.username || "",
|
||||||
hostname: cockpit.location.options.hostname || "",
|
hostname: cockpit.location.options.hostname || "",
|
||||||
|
search: cockpit.location.options.search || "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -763,7 +719,7 @@ class View extends React.Component {
|
||||||
* Assumes journalctl is not running.
|
* Assumes journalctl is not running.
|
||||||
*/
|
*/
|
||||||
journalctlStart() {
|
journalctlStart() {
|
||||||
let matches = ["_UID=" + this.uid, "+", "_EXE=/usr/bin/tlog-rec-session", "+", "_EXE=/usr/bin/tlog-rec", "+", "SYSLOG_IDENTIFIER=\"-tlog-rec-session\""];
|
let matches = ["_UID=" + this.uid, "+", "_EXE=/usr/bin/tlog-rec-session", "+", "_EXE=/usr/bin/tlog-rec", "+", "SYSLOG_IDENTIFIER=-tlog-rec-session"];
|
||||||
if (this.state.username && this.state.username !== "") {
|
if (this.state.username && this.state.username !== "") {
|
||||||
matches.push("TLOG_USER=" + this.state.username);
|
matches.push("TLOG_USER=" + this.state.username);
|
||||||
}
|
}
|
||||||
|
|
@ -781,7 +737,12 @@ class View extends React.Component {
|
||||||
options['until'] = this.state.date_until;
|
options['until'] = this.state.date_until;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.state.search && this.state.search !== "" && this.state.recordingID === null) {
|
||||||
|
options["grep"] = this.state.search;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.state.recordingID !== null) {
|
if (this.state.recordingID !== null) {
|
||||||
|
delete options["grep"];
|
||||||
matches.push("TLOG_REC=" + this.state.recordingID);
|
matches.push("TLOG_REC=" + this.state.recordingID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -894,7 +855,8 @@ class View extends React.Component {
|
||||||
if (this.state.date_since !== prevState.date_since ||
|
if (this.state.date_since !== prevState.date_since ||
|
||||||
this.state.date_until !== prevState.date_until ||
|
this.state.date_until !== prevState.date_until ||
|
||||||
this.state.username !== prevState.username ||
|
this.state.username !== prevState.username ||
|
||||||
this.state.hostname !== prevState.hostname
|
this.state.hostname !== prevState.hostname ||
|
||||||
|
this.state.search !== prevState.search
|
||||||
) {
|
) {
|
||||||
this.clearRecordings();
|
this.clearRecordings();
|
||||||
this.journalctlRestart();
|
this.journalctlRestart();
|
||||||
|
|
@ -929,7 +891,16 @@ class View extends React.Component {
|
||||||
<Datetimepicker value={this.state.date_until} onChange={this.handleDateUntilChange} />
|
<Datetimepicker value={this.state.date_until} onChange={this.handleDateUntilChange} />
|
||||||
</td>
|
</td>
|
||||||
<td className="top">
|
<td className="top">
|
||||||
<label className="control-label" htmlFor="username">{_("Username")}</label>
|
<label className="control-label" htmlFor="search">Search</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div className="input-group">
|
||||||
|
<input type="text" className="form-control" name="search" value={this.state.search}
|
||||||
|
onChange={this.handleInputChange} />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="top">
|
||||||
|
<label className="control-label" htmlFor="username">Username</label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
|
|
@ -972,7 +943,7 @@ class View extends React.Component {
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Recording recording={this.recordingMap[this.state.recordingID]} onTsChange={this.handleTsChange} logsTs={this.state.logsTs} />
|
<Recording recording={this.recordingMap[this.state.recordingID]} onTsChange={this.handleTsChange} logsTs={this.state.logsTs} search={this.state.search} />
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-md-12">
|
<div className="col-md-12">
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
import Player from "./player";
|
import Player from "./player";
|
||||||
|
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var React = require("react");
|
var React = require("react");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue