ESLint error and warning fixes

This commit is contained in:
Justin Stephenson 2023-04-18 14:51:13 -04:00
parent b73f42eb38
commit 0089d35bef
3 changed files with 252 additions and 198 deletions

View file

@ -16,7 +16,6 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>. * along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/ */
"use strict";
import React from "react"; import React from "react";
import { import {
@ -44,10 +43,10 @@ import {
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { ExclamationCircleIcon } from "@patternfly/react-icons"; import { ExclamationCircleIcon } from "@patternfly/react-icons";
import { global_danger_color_200 } from "@patternfly/react-tokens"; import { global_danger_color_200 } from "@patternfly/react-tokens";
import cockpit from 'cockpit';
const json = require('comment-json'); const json = require('comment-json');
const ini = require('ini'); const ini = require('ini');
const cockpit = require('cockpit');
const _ = cockpit.gettext; const _ = cockpit.gettext;
class GeneralConfig extends React.Component { class GeneralConfig extends React.Component {
@ -124,15 +123,15 @@ class GeneralConfig extends React.Component {
setConfig(data) { setConfig(data) {
delete data.configuration; delete data.configuration;
delete data.args; delete data.args;
var flattenObject = function(ob) { const flattenObject = function(ob) {
var toReturn = {}; const toReturn = {};
for (var i in ob) { for (const i in ob) {
if (!Object.prototype.hasOwnProperty.call(ob, i)) continue; if (!Object.prototype.hasOwnProperty.call(ob, i)) continue;
if ((typeof ob[i]) == 'object') { if ((typeof ob[i]) == 'object') {
var flatObject = flattenObject(ob[i]); const flatObject = flattenObject(ob[i]);
for (var x in flatObject) { for (const x in flatObject) {
if (!Object.prototype.hasOwnProperty.call(flatObject, x)) continue; if (!Object.prototype.hasOwnProperty.call(flatObject, x)) continue;
toReturn[i + '_' + x] = flatObject[x]; toReturn[i + '_' + x] = flatObject[x];
@ -203,13 +202,15 @@ class GeneralConfig extends React.Component {
<TextInput <TextInput
id="shell" id="shell"
value={this.state.shell} value={this.state.shell}
onChange={shell => this.setState({ shell })} /> onChange={shell => this.setState({ shell })}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Notice")}> <FormGroup label={_("Notice")}>
<TextInput <TextInput
id="notice" id="notice"
value={this.state.notice} value={this.state.notice}
onChange={notice => this.setState({ notice })} /> onChange={notice => this.setState({ notice })}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Latency")}> <FormGroup label={_("Latency")}>
<TextInput <TextInput
@ -217,7 +218,8 @@ class GeneralConfig extends React.Component {
type="number" type="number"
step="1" step="1"
value={this.state.latency} value={this.state.latency}
onChange={latency => this.setState({ latency })} /> onChange={latency => this.setState({ latency })}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Payload Size, bytes")}> <FormGroup label={_("Payload Size, bytes")}>
<TextInput <TextInput
@ -225,24 +227,28 @@ class GeneralConfig extends React.Component {
type="number" type="number"
step="1" step="1"
value={this.state.payload} value={this.state.payload}
onChange={payload => this.setState({ payload })} /> onChange={payload => this.setState({ payload })}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Logging")}> <FormGroup label={_("Logging")}>
<Checkbox <Checkbox
id="log_input" id="log_input"
isChecked={this.state.log_input} isChecked={this.state.log_input}
onChange={log_input => this.setState({ log_input })} onChange={log_input => this.setState({ log_input })}
label={_("User's Input")} /> label={_("User's Input")}
/>
<Checkbox <Checkbox
id="log_output" id="log_output"
isChecked={this.state.log_output} isChecked={this.state.log_output}
onChange={log_output => this.setState({ log_output })} onChange={log_output => this.setState({ log_output })}
label={_("User's Output")} /> label={_("User's Output")}
/>
<Checkbox <Checkbox
id="log_window" id="log_window"
isChecked={this.state.log_window} isChecked={this.state.log_window}
onChange={log_window => this.setState({ log_window })} onChange={log_window => this.setState({ log_window })}
label={_("Window Resize")} /> label={_("Window Resize")}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Limit Rate, bytes/sec")}> <FormGroup label={_("Limit Rate, bytes/sec")}>
<TextInput <TextInput
@ -250,7 +256,8 @@ class GeneralConfig extends React.Component {
type="number" type="number"
step="1" step="1"
value={this.state.limit_rate} value={this.state.limit_rate}
onChange={limit_rate => this.setState({ limit_rate })} /> onChange={limit_rate => this.setState({ limit_rate })}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Burst, bytes")}> <FormGroup label={_("Burst, bytes")}>
<TextInput <TextInput
@ -258,13 +265,15 @@ class GeneralConfig extends React.Component {
type="number" type="number"
step="1" step="1"
value={this.state.limit_burst} value={this.state.limit_burst}
onChange={limit_burst => this.setState({ limit_burst })} /> onChange={limit_burst => this.setState({ limit_burst })}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Logging Limit Action")}> <FormGroup label={_("Logging Limit Action")}>
<FormSelect <FormSelect
id="limit_action" id="limit_action"
value={this.state.limit_action} value={this.state.limit_action}
onChange={limit_action => this.setState({ limit_action })}> onChange={limit_action => this.setState({ limit_action })}
>
{[ {[
{ value: "", label: "" }, { value: "", label: "" },
{ value: "pass", label: _("Pass") }, { value: "pass", label: _("Pass") },
@ -274,7 +283,8 @@ class GeneralConfig extends React.Component {
<FormSelectOption <FormSelectOption
key={index} key={index}
value={option.value} value={option.value}
label={option.label} /> label={option.label}
/>
)} )}
</FormSelect> </FormSelect>
</FormGroup> </FormGroup>
@ -282,21 +292,24 @@ class GeneralConfig extends React.Component {
<TextInput <TextInput
id="file_path" id="file_path"
value={this.state.file_path} value={this.state.file_path}
onChange={file_path => this.setState({ file_path })} /> onChange={file_path => this.setState({ file_path })}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Syslog Facility")}> <FormGroup label={_("Syslog Facility")}>
<TextInput <TextInput
id="syslog_facility" id="syslog_facility"
value={this.state.syslog_facility} value={this.state.syslog_facility}
onChange={syslog_facility => onChange={syslog_facility =>
this.setState({ syslog_facility })} /> this.setState({ syslog_facility })}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Syslog Priority")}> <FormGroup label={_("Syslog Priority")}>
<FormSelect <FormSelect
id="syslog_priority" id="syslog_priority"
value={this.state.syslog_priority} value={this.state.syslog_priority}
onChange={syslog_priority => onChange={syslog_priority =>
this.setState({ syslog_priority })}> this.setState({ syslog_priority })}
>
{[ {[
{ value: "", label: "" }, { value: "", label: "" },
{ value: "info", label: _("Info") }, { value: "info", label: _("Info") },
@ -304,7 +317,8 @@ class GeneralConfig extends React.Component {
<FormSelectOption <FormSelectOption
key={index} key={index}
value={option.value} value={option.value}
label={option.label} /> label={option.label}
/>
)} )}
</FormSelect> </FormSelect>
</FormGroup> </FormGroup>
@ -313,7 +327,8 @@ class GeneralConfig extends React.Component {
id="journal_priority" id="journal_priority"
value={this.state.journal_priority} value={this.state.journal_priority}
onChange={journal_priority => onChange={journal_priority =>
this.setState({ journal_priority })}> this.setState({ journal_priority })}
>
{[ {[
{ value: "", label: "" }, { value: "", label: "" },
{ value: "info", label: _("Info") }, { value: "info", label: _("Info") },
@ -321,7 +336,8 @@ class GeneralConfig extends React.Component {
<FormSelectOption <FormSelectOption
key={index} key={index}
value={option.value} value={option.value}
label={option.label} /> label={option.label}
/>
)} )}
</FormSelect> </FormSelect>
</FormGroup> </FormGroup>
@ -331,14 +347,16 @@ class GeneralConfig extends React.Component {
isChecked={this.state.journal_augment} isChecked={this.state.journal_augment}
onChange={journal_augment => onChange={journal_augment =>
this.setState({ journal_augment })} this.setState({ journal_augment })}
label={_("Augment")} /> label={_("Augment")}
/>
</FormGroup> </FormGroup>
<FormGroup label={_("Writer")}> <FormGroup label={_("Writer")}>
<FormSelect <FormSelect
id="writer" id="writer"
value={this.state.writer} value={this.state.writer}
onChange={writer => onChange={writer =>
this.setState({ writer })}> this.setState({ writer })}
>
{[ {[
{ value: "", label: "" }, { value: "", label: "" },
{ value: "journal", label: _("Journal") }, { value: "journal", label: _("Journal") },
@ -348,7 +366,8 @@ class GeneralConfig extends React.Component {
<FormSelectOption <FormSelectOption
key={index} key={index}
value={option.value} value={option.value}
label={option.label} /> label={option.label}
/>
)} )}
</FormSelect> </FormSelect>
</FormGroup> </FormGroup>
@ -356,7 +375,8 @@ class GeneralConfig extends React.Component {
<Button <Button
id="btn-save-tlog-conf" id="btn-save-tlog-conf"
variant="primary" variant="primary"
onClick={this.handleSubmit}> onClick={this.handleSubmit}
>
{_("Save")} {_("Save")}
</Button> </Button>
{this.state.submitting === true && <Spinner size="lg" />} {this.state.submitting === true && <Spinner size="lg" />}
@ -368,7 +388,8 @@ class GeneralConfig extends React.Component {
<EmptyState variant={EmptyStateVariant.small}> <EmptyState variant={EmptyStateVariant.small}>
<EmptyStateIcon <EmptyStateIcon
icon={ExclamationCircleIcon} icon={ExclamationCircleIcon}
color={global_danger_color_200.value} /> color={global_danger_color_200.value}
/>
<Title headingLevel="h4" size="lg"> <Title headingLevel="h4" size="lg">
{_("There is no configuration file of tlog present in your system.")} {_("There is no configuration file of tlog present in your system.")}
</Title> </Title>
@ -413,15 +434,15 @@ class SssdConfig extends React.Component {
} }
restartSSSD() { restartSSSD() {
let sssd_cmd = ["systemctl", "restart", "sssd"]; const sssd_cmd = ["systemctl", "restart", "sssd"];
cockpit.spawn(sssd_cmd, { superuser: "require" }); cockpit.spawn(sssd_cmd, { superuser: "require" });
this.setState({ submitting: false }); this.setState({ submitting: false });
} }
confSave(obj) { confSave(obj) {
let chmod_cmd = ["chmod", "600", "/etc/sssd/conf.d/sssd-session-recording.conf"]; const chmod_cmd = ["chmod", "600", "/etc/sssd/conf.d/sssd-session-recording.conf"];
/* Update nsswitch, this will fail on RHEL8/F34 and lower as 'with-files-domain' feature is not added there */ /* Update nsswitch, this will fail on RHEL8/F34 and lower as 'with-files-domain' feature is not added there */
let authselect_cmd = ["authselect", "select", "sssd", "with-files-domain", "--force"]; const authselect_cmd = ["authselect", "select", "sssd", "with-files-domain", "--force"];
this.setState({ submitting: true }); this.setState({ submitting: true });
this.file.replace(obj).done(() => { this.file.replace(obj).done(() => {
cockpit.spawn(chmod_cmd, { superuser: "require" }) cockpit.spawn(chmod_cmd, { superuser: "require" })
@ -491,7 +512,8 @@ class SssdConfig extends React.Component {
<FormSelect <FormSelect
id="scope" id="scope"
value={this.state.scope} value={this.state.scope}
onChange={scope => this.setState({ scope })}> onChange={scope => this.setState({ scope })}
>
{[ {[
{ value: "none", label: _("None") }, { value: "none", label: _("None") },
{ value: "some", label: _("Some") }, { value: "some", label: _("Some") },
@ -500,7 +522,8 @@ class SssdConfig extends React.Component {
<FormSelectOption <FormSelectOption
key={index} key={index}
value={option.value} value={option.value}
label={option.label} /> label={option.label}
/>
)} )}
</FormSelect> </FormSelect>
</FormGroup> </FormGroup>
@ -542,7 +565,8 @@ class SssdConfig extends React.Component {
<Button <Button
id="btn-save-sssd-conf" id="btn-save-sssd-conf"
variant="primary" variant="primary"
onClick={this.handleSubmit}> onClick={this.handleSubmit}
>
{_("Save")} {_("Save")}
</Button> </Button>
{this.state.submitting === true && <Spinner size="lg" />} {this.state.submitting === true && <Spinner size="lg" />}
@ -577,7 +601,8 @@ groupProps={{ sticky: 'top' }}
{_("Settings")} {_("Settings")}
</BreadcrumbItem> </BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
}> }
>
<PageSection> <PageSection>
<Flex className="config-container"> <Flex className="config-container">
<GeneralConfig /> <GeneralConfig />

View file

@ -16,7 +16,6 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>. * along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/ */
"use strict";
import React from 'react'; import React from 'react';
import './player.css'; import './player.css';
import { Terminal as Term } from 'xterm'; import { Terminal as Term } from 'xterm';
@ -55,9 +54,9 @@ import {
MigrationIcon, MigrationIcon,
} from '@patternfly/react-icons'; } from '@patternfly/react-icons';
import cockpit from 'cockpit';
import { journal } from 'journal'; import { journal } from 'journal';
const cockpit = require("cockpit");
const _ = cockpit.gettext; const _ = cockpit.gettext;
const $ = require("jquery"); const $ = require("jquery");
@ -77,8 +76,8 @@ const padInt = function (n, w) {
*/ */
const formatDateTime = function (ms) { const formatDateTime = function (ms) {
/* Convert local timezone offset */ /* Convert local timezone offset */
let t = new Date(ms); const t = new Date(ms);
let z = t.getTimezoneOffset() * 60 * 1000; const z = t.getTimezoneOffset() * 60 * 1000;
let tLocal = t - z; let tLocal = t - z;
tLocal = new Date(tLocal); tLocal = new Date(tLocal);
let iso = tLocal.toISOString(); let iso = tLocal.toISOString();
@ -243,11 +242,10 @@ const PacketBuffer = class {
* Get an object field, verifying its presence and type. * Get an object field, verifying its presence and type.
*/ */
getValidField(object, field, type) { getValidField(object, field, type) {
let value;
if (!(field in object)) { if (!(field in object)) {
this.reportError("\"" + field + "\" field is missing"); this.reportError("\"" + field + "\" field is missing");
} }
value = object[field]; const value = object[field];
if (typeof (value) != typeof (type)) { if (typeof (value) != typeof (type)) {
this.reportError("invalid \"" + field + "\" field type: " + typeof (value)); this.reportError("invalid \"" + field + "\" field type: " + typeof (value));
} }
@ -294,7 +292,7 @@ const PacketBuffer = class {
/* Try to find an existing, matching tuple */ /* Try to find an existing, matching tuple */
for (i = 0; i < this.idxDfdList.length; i++) { for (i = 0; i < this.idxDfdList.length; i++) {
idxDfd = this.idxDfdList[i]; idxDfd = this.idxDfdList[i];
if (idxDfd[0] == idx) { if (idxDfd[0] === idx) {
return idxDfd[1].promise(); return idxDfd[1].promise();
} else if (idxDfd[0] > idx) { } else if (idxDfd[0] > idx) {
break; break;
@ -394,7 +392,7 @@ const PacketBuffer = class {
matches = this.timingRE.exec(timing); matches = this.timingRE.exec(timing);
if (matches === null) { if (matches === null) {
this.reportError(_("invalid timing string")); this.reportError(_("invalid timing string"));
} else if (matches[0] == "") { } else if (matches[0] === "") {
break; break;
} }
@ -403,14 +401,14 @@ const PacketBuffer = class {
/* Delay */ /* Delay */
case "+": case "+":
x = parseInt(matches[1], 10); x = parseInt(matches[1], 10);
if (x == 0) { if (x === 0) {
break; break;
} }
if (io.length > 0) { if (io.length > 0) {
this.addPacket({ this.addPacket({
pos: this.pos, pos: this.pos,
is_io: true, is_io: true,
is_output: is_output, is_output,
io: io.join() io: io.join()
}); });
io = []; io = [];
@ -420,15 +418,15 @@ const PacketBuffer = class {
/* Text or binary input */ /* Text or binary input */
case "<": case "<":
case "[": case "[":
x = parseInt(matches[(t == "<") ? 2 : 3], 10); x = parseInt(matches[(t === "<") ? 2 : 3], 10);
if (x == 0) { if (x === 0) {
break; break;
} }
if (io.length > 0 && is_output) { if (io.length > 0 && is_output) {
this.addPacket({ this.addPacket({
pos: this.pos, pos: this.pos,
is_io: true, is_io: true,
is_output: is_output, is_output,
io: io.join() io: io.join()
}); });
io = []; io = [];
@ -436,7 +434,7 @@ const PacketBuffer = class {
is_output = false; is_output = false;
/* Add (replacement) input characters */ /* Add (replacement) input characters */
s = in_txt.slice(in_txt_pos, in_txt_pos += x); s = in_txt.slice(in_txt_pos, in_txt_pos += x);
if (s.length != x) { if (s.length !== x) {
this.reportError(_("timing entry out of input bounds")); this.reportError(_("timing entry out of input bounds"));
} }
io.push(s); io.push(s);
@ -444,15 +442,15 @@ const PacketBuffer = class {
/* Text or binary output */ /* Text or binary output */
case ">": case ">":
case "]": case "]":
x = parseInt(matches[(t == ">") ? 5 : 6], 10); x = parseInt(matches[(t === ">") ? 5 : 6], 10);
if (x == 0) { if (x === 0) {
break; break;
} }
if (io.length > 0 && !is_output) { if (io.length > 0 && !is_output) {
this.addPacket({ this.addPacket({
pos: this.pos, pos: this.pos,
is_io: true, is_io: true,
is_output: is_output, is_output,
io: io.join() io: io.join()
}); });
io = []; io = [];
@ -460,7 +458,7 @@ const PacketBuffer = class {
is_output = true; is_output = true;
/* Add (replacement) output characters */ /* Add (replacement) output characters */
s = out_txt.slice(out_txt_pos, out_txt_pos += x); s = out_txt.slice(out_txt_pos, out_txt_pos += x);
if (s.length != x) { if (s.length !== x) {
this.reportError(_("timing entry out of output bounds")); this.reportError(_("timing entry out of output bounds"));
} }
io.push(s); io.push(s);
@ -469,14 +467,14 @@ const PacketBuffer = class {
case "=": case "=":
x = parseInt(matches[8], 10); x = parseInt(matches[8], 10);
y = parseInt(matches[9], 10); y = parseInt(matches[9], 10);
if (x == this.width && y == this.height) { if (x === this.width && y === this.height) {
break; break;
} }
if (io.length > 0) { if (io.length > 0) {
this.addPacket({ this.addPacket({
pos: this.pos, pos: this.pos,
is_io: true, is_io: true,
is_output: is_output, is_output,
io: io.join() io: io.join()
}); });
io = []; io = [];
@ -490,6 +488,9 @@ const PacketBuffer = class {
this.width = x; this.width = x;
this.height = y; this.height = y;
break; break;
default:
// continue
break;
} }
} }
@ -504,7 +505,7 @@ const PacketBuffer = class {
this.addPacket({ this.addPacket({
pos: this.pos, pos: this.pos,
is_io: true, is_io: true,
is_output: is_output, is_output,
io: io.join() io: io.join()
}); });
} }
@ -514,17 +515,12 @@ const PacketBuffer = class {
* Parse packets out of a tlog message and add them to the buffer. * Parse packets out of a tlog message and add them to the buffer.
*/ */
parseMessage(message) { parseMessage(message) {
let matches;
let ver;
let id;
let pos;
const number = Number(); const number = Number();
const string = String(); const string = String();
/* Check version */ /* Check version */
ver = this.getValidField(message, "ver", string); const ver = this.getValidField(message, "ver", string);
matches = ver.match("^(\\d+)\\.(\\d+)$"); const matches = ver.match("^(\\d+)\\.(\\d+)$");
if (matches === null || matches[1] > 2) { if (matches === null || matches[1] > 2) {
this.reportError("\"ver\" field has invalid value: " + ver); this.reportError("\"ver\" field has invalid value: " + ver);
} }
@ -532,13 +528,13 @@ const PacketBuffer = class {
/* TODO Perhaps check host, rec, user, term, and session fields */ /* TODO Perhaps check host, rec, user, term, and session fields */
/* Extract message ID */ /* Extract message ID */
id = this.getValidField(message, "id", number); const id = this.getValidField(message, "id", number);
if (id <= this.id) { if (id <= this.id) {
this.reportError("out of order \"id\" field value: " + id); this.reportError("out of order \"id\" field value: " + id);
} }
/* Extract message time position */ /* Extract message time position */
pos = this.getValidField(message, "pos", number); const pos = this.getValidField(message, "pos", number);
if (pos < this.message_pos) { if (pos < this.message_pos) {
this.reportError("out of order \"pos\" field value: " + pos); this.reportError("out of order \"pos\" field value: " + pos);
} }
@ -612,8 +608,7 @@ const PacketBuffer = class {
this.journalctl = journal.journalctl( this.journalctl = journal.journalctl(
this.matchList, this.matchList,
{ {
cursor: this.cursor, cursor: this.cursor, follow: true, merge: true, count: "all"
follow: true, merge: true, count: "all"
}); });
this.journalctl.fail(this.handleError); this.journalctl.fail(this.handleError);
this.journalctl.stream(this.handleStream); this.journalctl.stream(this.handleStream);
@ -634,14 +629,14 @@ class Search extends React.Component {
this.handleStream = this.handleStream.bind(this); this.handleStream = this.handleStream.bind(this);
this.handleError = this.handleError.bind(this); this.handleError = this.handleError.bind(this);
this.handleSearchSubmit = this.handleSearchSubmit.bind(this); this.handleSearchSubmit = this.handleSearchSubmit.bind(this);
this.clearSearchResults = this.clearSearchResults.bind(this); this.handleClearSearchResults = this.handleClearSearchResults.bind(this);
this.state = { this.state = {
search: cockpit.location.options.search_rec || cockpit.location.options.search || "", search: cockpit.location.options.search_rec || cockpit.location.options.search || "",
}; };
} }
handleInputChange(name, value) { handleInputChange(name, value) {
event.preventDefault();
const state = {}; const state = {};
state[name] = value; state[name] = value;
this.setState(state); this.setState(state);
@ -669,14 +664,14 @@ class Search extends React.Component {
/> />
); );
}); });
this.setState({ items: items }); this.setState({ items });
} }
handleError(data) { handleError(data) {
this.props.errorService.addMessage(data); this.props.errorService.addMessage(data);
} }
clearSearchResults() { handleClearSearchResults() {
delete cockpit.location.options.search; delete cockpit.location.options.search;
cockpit.location.go(cockpit.location.path[0], cockpit.location.options); cockpit.location.go(cockpit.location.path[0], cockpit.location.options);
this.setState({ search: "" }); this.setState({ search: "" });
@ -697,15 +692,18 @@ class Search extends React.Component {
id="search_rec" id="search_rec"
type="search" type="search"
value={this.state.search} value={this.state.search}
onChange={value => this.handleInputChange("search", value)} /> onChange={value => this.handleInputChange("search", value)}
/>
<Button <Button
variant="control" variant="control"
onClick={this.handleSearchSubmit}> onClick={this.handleSearchSubmit}
>
<SearchIcon /> <SearchIcon />
</Button> </Button>
<Button <Button
variant="control" variant="control"
onClick={this.clearSearchResults}> onClick={this.handleClearSearchResults}
>
<MinusIcon /> <MinusIcon />
</Button> </Button>
</InputGroup> </InputGroup>
@ -734,21 +732,21 @@ export class Player extends React.Component {
this.handlePacket = this.handlePacket.bind(this); this.handlePacket = this.handlePacket.bind(this);
this.handleError = this.handleError.bind(this); this.handleError = this.handleError.bind(this);
this.handleTitleChange = this.handleTitleChange.bind(this); this.handleTitleChange = this.handleTitleChange.bind(this);
this.rewindToStart = this.rewindToStart.bind(this); this.handleRewindToStart = this.handleRewindToStart.bind(this);
this.playPauseToggle = this.playPauseToggle.bind(this); this.handlePlayPauseToggle = this.handlePlayPauseToggle.bind(this);
this.play = this.play.bind(this); this.play = this.play.bind(this);
this.pause = this.pause.bind(this); this.pause = this.pause.bind(this);
this.speedUp = this.speedUp.bind(this); this.handleSpeedUp = this.handleSpeedUp.bind(this);
this.speedDown = this.speedDown.bind(this); this.handleSpeedDown = this.handleSpeedDown.bind(this);
this.speedReset = this.speedReset.bind(this); this.handleSpeedReset = this.handleSpeedReset.bind(this);
this.fastForwardToEnd = this.fastForwardToEnd.bind(this); this.handleFastForwardToEnd = this.handleFastForwardToEnd.bind(this);
this.skipFrame = this.skipFrame.bind(this); this.handleSkipFrame = this.handleSkipFrame.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this);
this.sync = this.sync.bind(this); this.sync = this.sync.bind(this);
this.zoomIn = this.zoomIn.bind(this); this.handleZoomIn = this.handleZoomIn.bind(this);
this.zoomOut = this.zoomOut.bind(this); this.handleZoomOut = this.handleZoomOut.bind(this);
this.fitTo = this.fitTo.bind(this); this.handleFitTo = this.handleFitTo.bind(this);
this.dragPan = this.dragPan.bind(this); this.handleDragPan = this.handleDragPan.bind(this);
this.dragPanEnable = this.dragPanEnable.bind(this); this.dragPanEnable = this.dragPanEnable.bind(this);
this.dragPanDisable = this.dragPanDisable.bind(this); this.dragPanDisable = this.dragPanDisable.bind(this);
this.zoom = this.zoom.bind(this); this.zoom = this.zoom.bind(this);
@ -756,6 +754,8 @@ export class Player extends React.Component {
this.sendInput = this.sendInput.bind(this); this.sendInput = this.sendInput.bind(this);
this.clearInputPlayer = this.clearInputPlayer.bind(this); this.clearInputPlayer = this.clearInputPlayer.bind(this);
this.handleInfoClick = this.handleInfoClick.bind(this); this.handleInfoClick = this.handleInfoClick.bind(this);
this.wrapperRef = React.createRef();
this.termRef = React.createRef();
this.handleProgressClick = this.handleProgressClick.bind(this); this.handleProgressClick = this.handleProgressClick.bind(this);
this.state = { this.state = {
@ -793,6 +793,10 @@ export class Player extends React.Component {
this.containerHeight = 400; this.containerHeight = 400;
this.setScrollwrapRef = element => {
this.scrollwrapRef = element;
};
/* Auto-loading buffer of recording's packets */ /* Auto-loading buffer of recording's packets */
this.error_service = new ErrorService(); this.error_service = new ErrorService();
this.reportError = this.error_service.addMessage; this.reportError = this.error_service.addMessage;
@ -891,7 +895,7 @@ export class Player extends React.Component {
} }
_transform(width, height) { _transform(width, height) {
var relation = Math.min( const relation = Math.min(
this.state.containerWidth / this.state.term.element.offsetWidth, this.state.containerWidth / this.state.term.element.offsetWidth,
this.containerHeight / this.state.term.element.offsetHeight this.containerHeight / this.state.term.element.offsetHeight
); );
@ -1008,7 +1012,7 @@ export class Player extends React.Component {
} }
} }
playPauseToggle() { handlePlayPauseToggle() {
this.setState({ paused: !this.state.paused }); this.setState({ paused: !this.state.paused });
} }
@ -1020,21 +1024,21 @@ export class Player extends React.Component {
this.setState({ paused: true }); this.setState({ paused: true });
} }
speedUp() { handleSpeedUp() {
const speedExp = this.state.speedExp; const speedExp = this.state.speedExp;
if (speedExp < 4) { if (speedExp < 4) {
this.setState({ speedExp: speedExp + 1 }); this.setState({ speedExp: speedExp + 1 });
} }
} }
speedDown() { handleSpeedDown() {
const speedExp = this.state.speedExp; const speedExp = this.state.speedExp;
if (speedExp > -4) { if (speedExp > -4) {
this.setState({ speedExp: speedExp - 1 }); this.setState({ speedExp: speedExp - 1 });
} }
} }
speedReset() { handleSpeedReset() {
this.setState({ speedExp: 0 }); this.setState({ speedExp: 0 });
} }
@ -1042,7 +1046,7 @@ export class Player extends React.Component {
this.setState({ input: "" }); this.setState({ input: "" });
} }
rewindToStart() { handleRewindToStart() {
this.clearInputPlayer(); this.clearInputPlayer();
this.reset(); this.reset();
this.sync(); this.sync();
@ -1051,7 +1055,7 @@ export class Player extends React.Component {
} }
} }
fastForwardToEnd() { handleFastForwardToEnd() {
this.fastForwardTo = Infinity; this.fastForwardTo = Infinity;
this.sync(); this.sync();
} }
@ -1064,23 +1068,23 @@ export class Player extends React.Component {
this.sync(); this.sync();
} }
skipFrame() { handleSkipFrame() {
this.skip = true; this.skip = true;
this.sync(); this.sync();
} }
handleKeyDown(event) { handleKeyDown(event) {
const keyCodesFuncs = { const keyCodesFuncs = {
P: this.playPauseToggle, P: this.handlePlayPauseToggle,
"}": this.speedUp, "}": this.handleSpeedUp,
"{": this.speedDown, "{": this.handleSpeedDown,
Backspace: this.speedReset, Backspace: this.handleSpeedReset,
".": this.skipFrame, ".": this.handleSkipFrame,
G: this.fastForwardToEnd, G: this.handleFastForwardToEnd,
R: this.rewindToStart, R: this.handleRewindToStart,
"+": this.zoomIn, "+": this.handleZoomIn,
"=": this.zoomIn, "=": this.handleZoomIn,
"-": this.zoomOut, "-": this.handleZoomOut,
Z: this.fitIn, Z: this.fitIn,
}; };
if (event.target.nodeName.toLowerCase() !== 'input') { if (event.target.nodeName.toLowerCase() !== 'input') {
@ -1092,7 +1096,7 @@ export class Player extends React.Component {
zoom(scale) { zoom(scale) {
if (scale.toFixed(6) === this.state.scale_initial.toFixed(6)) { if (scale.toFixed(6) === this.state.scale_initial.toFixed(6)) {
this.fitTo(); this.handleFitTo();
} else { } else {
this.setState({ this.setState({
term_top_style: "0", term_top_style: "0",
@ -1100,27 +1104,27 @@ export class Player extends React.Component {
term_translate: "0, 0", term_translate: "0, 0",
scale_lock: true, scale_lock: true,
term_scroll: "auto", term_scroll: "auto",
scale: scale, scale,
term_zoom_max: false, term_zoom_max: false,
term_zoom_min: false, term_zoom_min: false,
}); });
} }
} }
dragPan() { handleDragPan() {
(this.state.drag_pan ? this.dragPanDisable() : this.dragPanEnable()); (this.state.drag_pan ? this.dragPanDisable() : this.dragPanEnable());
} }
dragPanEnable() { dragPanEnable() {
this.setState({ drag_pan: true }); this.setState({ drag_pan: true });
const scrollwrap = this.refs.scrollwrap; const scrollwrap = this.scrollwrapRef;
let clicked = false; let clicked = false;
let clickX; let clickX;
let clickY; let clickY;
$(this.refs.scrollwrap).on({ $(this.scrollwrapRef).on({
mousemove: function(e) { mousemove: function(e) {
clicked && updateScrollPos(e); clicked && updateScrollPos(e);
}, },
@ -1144,13 +1148,13 @@ export class Player extends React.Component {
dragPanDisable() { dragPanDisable() {
this.setState({ drag_pan: false }); this.setState({ drag_pan: false });
const scrollwrap = this.refs.scrollwrap; const scrollwrap = this.scrollwrapRef;
$(scrollwrap).off("mousemove"); $(scrollwrap).off("mousemove");
$(scrollwrap).off("mousedown"); $(scrollwrap).off("mousedown");
$(scrollwrap).off("mouseup"); $(scrollwrap).off("mouseup");
} }
zoomIn() { handleZoomIn() {
let scale = this.state.scale; let scale = this.state.scale;
if (scale < 2.1) { if (scale < 2.1) {
scale = scale + 0.1; scale = scale + 0.1;
@ -1160,7 +1164,7 @@ export class Player extends React.Component {
} }
} }
zoomOut() { handleZoomOut() {
let scale = this.state.scale; let scale = this.state.scale;
if (scale >= 0.2) { if (scale >= 0.2) {
scale = scale - 0.1; scale = scale - 0.1;
@ -1170,7 +1174,7 @@ export class Player extends React.Component {
} }
} }
fitTo() { handleFitTo() {
this.setState({ this.setState({
term_top_style: "50%", term_top_style: "50%",
term_left_style: "50%", term_left_style: "50%",
@ -1182,15 +1186,17 @@ export class Player extends React.Component {
} }
componentDidMount() { componentDidMount() {
this.state.term.on('title', this.handleTitleChange); this.state.term.onData((data) => {
this.handleTitleChange();
});
window.addEventListener("keydown", this.handleKeyDown, false); window.addEventListener("keydown", this.handleKeyDown, false);
if (this.refs.wrapper.offsetWidth) { if (this.wrapperRef.offsetWidth) {
this.setState({ containerWidth: this.refs.wrapper.offsetWidth }); this.setState({ containerWidth: this.wrapperRef.offsetWidth });
} }
/* Open the terminal */ /* Open the terminal */
this.state.term.open(this.refs.term); this.state.term.open(this.termRef.current);
window.setInterval(this.sync, 100); window.setInterval(this.sync, 100);
/* Reset playback */ /* Reset playback */
this.reset(); this.reset();
@ -1199,15 +1205,15 @@ export class Player extends React.Component {
componentDidUpdate(prevProps, prevState) { componentDidUpdate(prevProps, prevState) {
/* If we changed pause state or speed exponent */ /* If we changed pause state or speed exponent */
if (this.state.paused != prevState.paused || if (this.state.paused !== prevState.paused ||
this.state.speedExp != prevState.speedExp) { this.state.speedExp !== prevState.speedExp) {
this.speed = Math.pow(2, this.state.speedExp); this.speed = Math.pow(2, this.state.speedExp);
this.sync(); this.sync();
} }
if (this.state.input != prevState.input) { if (this.state.input !== prevState.input) {
scrollToBottom("input-textarea"); scrollToBottom("input-textarea");
} }
if (prevProps.logsTs != this.props.logsTs) { if (prevProps.logsTs !== this.props.logsTs) {
this.fastForwardToTS(this.props.logsTs); this.fastForwardToTS(this.props.logsTs);
} }
} }
@ -1266,7 +1272,8 @@ export class Player extends React.Component {
valueText={timeStr} valueText={timeStr}
label={timeStr} label={timeStr}
value={this.state.curTS} value={this.state.curTS}
onClick={this.handleProgressClick} /> onClick={this.handleProgressClick}
/>
); );
const playbackControls = ( const playbackControls = (
@ -1277,7 +1284,7 @@ export class Player extends React.Component {
id="player-play-pause" id="player-play-pause"
title="Play/Pause - Hotkey: p" title="Play/Pause - Hotkey: p"
type="button" type="button"
onClick={this.playPauseToggle} onClick={this.handlePlayPauseToggle}
> >
{this.state.paused ? <PlayIcon /> : <PauseIcon />} {this.state.paused ? <PlayIcon /> : <PauseIcon />}
</Button> </Button>
@ -1288,7 +1295,7 @@ export class Player extends React.Component {
id="player-skip-frame" id="player-skip-frame"
title="Skip Frame - Hotkey: ." title="Skip Frame - Hotkey: ."
type="button" type="button"
onClick={this.skipFrame} onClick={this.handleSkipFrame}
> >
<ArrowRightIcon /> <ArrowRightIcon />
</Button> </Button>
@ -1299,7 +1306,7 @@ export class Player extends React.Component {
id="player-restart" id="player-restart"
title="Restart Playback - Hotkey: Shift-R" title="Restart Playback - Hotkey: Shift-R"
type="button" type="button"
onClick={this.rewindToStart} onClick={this.handleRewindToStart}
> >
<UndoIcon /> <UndoIcon />
</Button> </Button>
@ -1310,7 +1317,7 @@ export class Player extends React.Component {
id="player-fast-forward" id="player-fast-forward"
title="Fast-forward to end - Hotkey: Shift-G" title="Fast-forward to end - Hotkey: Shift-G"
type="button" type="button"
onClick={this.fastForwardToEnd} onClick={this.handleFastForwardToEnd}
> >
<RedoIcon /> <RedoIcon />
</Button> </Button>
@ -1321,7 +1328,7 @@ export class Player extends React.Component {
id="player-speed-down" id="player-speed-down"
title="Speed /2 - Hotkey: {" title="Speed /2 - Hotkey: {"
type="button" type="button"
onClick={this.speedDown} onClick={this.handleSpeedDown}
> >
/2 /2
</Button> </Button>
@ -1332,7 +1339,7 @@ export class Player extends React.Component {
id="player-speed-up" id="player-speed-up"
title="Speed x2 - Hotkey: }" title="Speed x2 - Hotkey: }"
type="button" type="button"
onClick={this.speedUp} onClick={this.handleSpeedUp}
> >
x2 x2
</Button> </Button>
@ -1340,7 +1347,7 @@ export class Player extends React.Component {
{speedStr !== "" && {speedStr !== "" &&
<ToolbarItem> <ToolbarItem>
<ChipGroup categoryName="speed"> <ChipGroup categoryName="speed">
<Chip onClick={this.speedReset}> <Chip onClick={this.handleSpeedReset}>
<span id="player-speed">{speedStr}</span> <span id="player-speed">{speedStr}</span>
</Chip> </Chip>
</ChipGroup> </ChipGroup>
@ -1355,7 +1362,7 @@ export class Player extends React.Component {
variant="plain" variant="plain"
id="player-drag-pan" id="player-drag-pan"
title="Drag'n'Pan" title="Drag'n'Pan"
onClick={this.dragPan} onClick={this.handleDragPan}
> >
{this.state.drag_pan ? <ThumbtackIcon /> : <MigrationIcon />} {this.state.drag_pan ? <ThumbtackIcon /> : <MigrationIcon />}
</Button> </Button>
@ -1366,7 +1373,7 @@ export class Player extends React.Component {
id="player-zoom-in" id="player-zoom-in"
title="Zoom In - Hotkey: =" title="Zoom In - Hotkey: ="
type="button" type="button"
onClick={this.zoomIn} onClick={this.handleZoomIn}
disabled={this.state.term_zoom_max} disabled={this.state.term_zoom_max}
> >
<SearchPlusIcon /> <SearchPlusIcon />
@ -1378,7 +1385,7 @@ export class Player extends React.Component {
id="player-fit-to" id="player-fit-to"
title="Fit To - Hotkey: Z" title="Fit To - Hotkey: Z"
type="button" type="button"
onClick={this.fitTo} onClick={this.handleFitTo}
> >
<ExpandIcon /> <ExpandIcon />
</Button> </Button>
@ -1389,7 +1396,7 @@ export class Player extends React.Component {
id="player-zoom-out" id="player-zoom-out"
title="Zoom Out - Hotkey: -" title="Zoom Out - Hotkey: -"
type="button" type="button"
onClick={this.zoomOut} onClick={this.handleZoomOut}
disabled={this.state.term_zoom_min} disabled={this.state.term_zoom_min}
> >
<SearchMinusIcon /> <SearchMinusIcon />
@ -1410,7 +1417,8 @@ export class Player extends React.Component {
play={this.play} play={this.play}
pause={this.pause} pause={this.pause}
paused={this.state.paused} paused={this.state.paused}
errorService={this.error_service} /> errorService={this.error_service}
/>
<ErrorList list={this.error_service.errors} /> <ErrorList list={this.error_service.errors} />
</ToolbarContent> </ToolbarContent>
</Toolbar> </Toolbar>
@ -1436,7 +1444,8 @@ export class Player extends React.Component {
dataListCells={[ dataListCells={[
<DataListCell key="name">{item.name}</DataListCell>, <DataListCell key="name">{item.name}</DataListCell>,
<DataListCell key="value">{item.value}</DataListCell> <DataListCell key="value">{item.value}</DataListCell>
]} /> ]}
/>
</DataListItemRow> </DataListItemRow>
</DataListItem> </DataListItem>
) )
@ -1449,7 +1458,8 @@ export class Player extends React.Component {
id="btn-recording-info" id="btn-recording-info"
toggleText={_("Recording Info")} toggleText={_("Recording Info")}
onToggle={this.handleInfoClick} onToggle={this.handleInfoClick}
isExpanded={this.state.infoEnabled === true}> isExpanded={this.state.infoEnabled === true}
>
{recordingInfo} {recordingInfo}
</ExpandableSection> </ExpandableSection>
); );
@ -1457,7 +1467,7 @@ 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 ref="wrapper" className="panel panel-default"> <div ref={this.wrapperRef} className="panel panel-default">
<div className="panel-heading"> <div className="panel-heading">
<span>{this.state.title}</span> <span>{this.state.title}</span>
</div> </div>
@ -1465,12 +1475,14 @@ export class Player extends React.Component {
<div <div
className={(this.state.drag_pan ? "dragnpan" : "")} className={(this.state.drag_pan ? "dragnpan" : "")}
style={scrollwrap} style={scrollwrap}
ref="scrollwrap"> ref={this.setScrollwrapRef}
>
<div <div
ref="term" ref={this.termRef}
className="console-ct" className="console-ct"
key={this.state.term} key={this.state.term}
style={style} /> style={style}
/>
</div> </div>
</div> </div>
{progress} {progress}
@ -1484,6 +1496,6 @@ export class Player extends React.Component {
componentWillUnmount() { componentWillUnmount() {
this.buf.stop(); this.buf.stop();
window.removeEventListener("keydown", this.handleKeyDown, false); window.removeEventListener("keydown", this.handleKeyDown, false);
this.state.term.destroy(); this.state.term.dispose();
} }
} }

View file

@ -16,8 +16,6 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>. * along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/ */
"use strict";
import React from "react"; import React from "react";
import { import {
Breadcrumb, BreadcrumbItem, Breadcrumb, BreadcrumbItem,
@ -58,12 +56,12 @@ import {
PlusIcon, PlusIcon,
SearchIcon SearchIcon
} from "@patternfly/react-icons"; } from "@patternfly/react-icons";
import cockpit from 'cockpit';
import { global_danger_color_200 } from "@patternfly/react-tokens"; import { global_danger_color_200 } from "@patternfly/react-tokens";
import { debounce } from 'throttle-debounce'; import { debounce } from 'throttle-debounce';
import { journal } from 'journal'; import { journal } from 'journal';
const $ = require("jquery"); const $ = require("jquery");
const cockpit = require("cockpit");
const _ = cockpit.gettext; const _ = cockpit.gettext;
const Player = require("./player.jsx"); const Player = require("./player.jsx");
const Config = require("./config.jsx"); const Config = require("./config.jsx");
@ -88,8 +86,8 @@ const padInt = function (n, w) {
*/ */
const formatDateTime = function (ms) { const formatDateTime = function (ms) {
/* Convert local timezone offset */ /* Convert local timezone offset */
let t = new Date(ms); const t = new Date(ms);
let z = t.getTimezoneOffset() * 60 * 1000; const z = t.getTimezoneOffset() * 60 * 1000;
let tLocal = t - z; let tLocal = t - z;
tLocal = new Date(tLocal); tLocal = new Date(tLocal);
let iso = tLocal.toISOString(); let iso = tLocal.toISOString();
@ -148,9 +146,9 @@ function LogElement(props) {
const timeClick = function(_e) { const timeClick = function(_e) {
const ts = entry_timestamp - start; const ts = entry_timestamp - start;
if (ts > 0) { if (ts > 0) {
props.jumpToTs(ts); props.onJumpToTs(ts);
} else { } else {
props.jumpToTs(0); props.onJumpToTs(0);
} }
}; };
const messageClick = () => { const messageClick = () => {
@ -159,7 +157,8 @@ function LogElement(props) {
win.focus(); win.focus();
}; };
const cells = <DataListItemCells const cells = (
<DataListItemCells
dataListCells={[ dataListCells={[
<DataListCell key="row"> <DataListCell key="row">
<ExclamationTriangleIcon /> <ExclamationTriangleIcon />
@ -170,7 +169,9 @@ function LogElement(props) {
<CardBody>{entry.MESSAGE}</CardBody> <CardBody>{entry.MESSAGE}</CardBody>
</Card> </Card>
</DataListCell> </DataListCell>
]} />; ]}
/>
);
return ( return (
<DataListItem> <DataListItem>
@ -187,7 +188,8 @@ function LogsView(props) {
entry={entry} entry={entry}
start={start} start={start}
end={end} end={end}
jumpToTs={props.jumpToTs} /> onJumpToTs={props.onJumpToTs}
/>
); );
return ( return (
<DataList>{rows}</DataList> <DataList>{rows}</DataList>
@ -201,7 +203,7 @@ class Logs extends React.Component {
this.journalctlIngest = this.journalctlIngest.bind(this); this.journalctlIngest = this.journalctlIngest.bind(this);
this.journalctlPrepend = this.journalctlPrepend.bind(this); this.journalctlPrepend = this.journalctlPrepend.bind(this);
this.getLogs = this.getLogs.bind(this); this.getLogs = this.getLogs.bind(this);
this.loadLater = this.loadLater.bind(this); this.handleLoadLater = this.handleLoadLater.bind(this);
this.loadForTs = this.loadForTs.bind(this); this.loadForTs = this.loadForTs.bind(this);
this.journalCtl = null; this.journalCtl = null;
this.entries = []; this.entries = [];
@ -224,7 +226,7 @@ class Logs extends React.Component {
if (entryList.length > 0) { if (entryList.length > 0) {
this.entries.push(...entryList); this.entries.push(...entryList);
const after = this.entries[this.entries.length - 1].__CURSOR; const after = this.entries[this.entries.length - 1].__CURSOR;
this.setState({ entries: this.entries, after: after }); this.setState({ entries: this.entries, after });
} }
} }
@ -274,7 +276,7 @@ class Logs extends React.Component {
} }
} }
loadLater() { handleLoadLater() {
this.start = this.end; this.start = this.end;
this.end = this.end + 3600; this.end = this.end + 3600;
this.getLogs(); this.getLogs();
@ -335,12 +337,14 @@ class Logs extends React.Component {
entries={this.state.entries} entries={this.state.entries}
start={this.props.recording.start} start={this.props.recording.start}
end={this.props.recording.end} end={this.props.recording.end}
jumpToTs={this.props.jumpToTs} /> onJumpToTs={this.props.onJumpToTs}
/>
<Bullseye> <Bullseye>
<Button <Button
variant="secondary" variant="secondary"
icon={<PlusIcon />} icon={<PlusIcon />}
onClick={this.loadLater}> onClick={this.handleLoadLater}
>
{_("Load later entries")} {_("Load later entries")}
</Button> </Button>
</Bullseye> </Bullseye>
@ -359,11 +363,12 @@ class Logs extends React.Component {
class Recording extends React.Component { class Recording extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.goBackToList = this.goBackToList.bind(this); this.handleGoBackToList = this.handleGoBackToList.bind(this);
this.handleTsChange = this.handleTsChange.bind(this); this.handleTsChange = this.handleTsChange.bind(this);
this.handleLogTsChange = this.handleLogTsChange.bind(this); this.handleLogTsChange = this.handleLogTsChange.bind(this);
this.handleLogsClick = this.handleLogsClick.bind(this); this.handleLogsClick = this.handleLogsClick.bind(this);
this.handleLogsReset = this.handleLogsReset.bind(this); this.handleLogsReset = this.handleLogsReset.bind(this);
this.playerRef = React.createRef();
this.state = { this.state = {
curTs: null, curTs: null,
logsTs: null, logsTs: null,
@ -389,7 +394,7 @@ class Recording extends React.Component {
}); });
} }
goBackToList() { handleGoBackToList() {
if (cockpit.location.path[0]) { if (cockpit.location.path[0]) {
if ("search_rec" in cockpit.location.options) { if ("search_rec" in cockpit.location.options) {
delete cockpit.location.options.search_rec; delete cockpit.location.options.search_rec;
@ -420,33 +425,37 @@ groupProps={{ sticky: 'top' }}
isBreadcrumbGrouped isBreadcrumbGrouped
breadcrumb={ breadcrumb={
<Breadcrumb className='machines-listing-breadcrumb'> <Breadcrumb className='machines-listing-breadcrumb'>
<BreadcrumbItem to='#' onClick={this.goBackToList}> <BreadcrumbItem to='#' onClick={this.handleGoBackToList}>
{_("Session Recording")} {_("Session Recording")}
</BreadcrumbItem> </BreadcrumbItem>
<BreadcrumbItem isActive> <BreadcrumbItem isActive>
{_("Current recording")} {_("Current recording")}
</BreadcrumbItem> </BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
}> }
>
<PageSection> <PageSection>
<Player.Player <Player.Player
ref="player" ref={this.playerRef}
matchList={this.props.recording.matchList} matchList={this.props.recording.matchList}
logsTs={this.logsTs} logsTs={this.logsTs}
search={this.props.search} search={this.props.search}
onTsChange={this.handleTsChange} onTsChange={this.handleTsChange}
recording={r} recording={r}
logsEnabled={this.state.logsEnabled} logsEnabled={this.state.logsEnabled}
onRewindStart={this.handleLogsReset} /> onRewindStart={this.handleLogsReset}
/>
<ExpandableSection <ExpandableSection
id="btn-logs-view" id="btn-logs-view"
toggleText={_("Logs View")} toggleText={_("Logs View")}
onToggle={this.handleLogsClick} onToggle={this.handleLogsClick}
isExpanded={this.state.logsEnabled === true}> isExpanded={this.state.logsEnabled === true}
>
<Logs <Logs
recording={this.props.recording} recording={this.props.recording}
curTs={this.state.curTs} curTs={this.state.curTs}
jumpToTs={this.handleLogTsChange} /> onJumpToTs={this.handleLogTsChange}
/>
</ExpandableSection> </ExpandableSection>
</PageSection> </PageSection>
</Page> </Page>
@ -463,9 +472,8 @@ groupProps={{ sticky: 'top' }}
class RecordingList extends React.Component { class RecordingList extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.handleOnSort = this.handleOnSort.bind(this);
this.onSort = this.onSort.bind(this); this.handleRowClick = this.handleRowClick.bind(this);
this.rowClickHandler = this.rowClickHandler.bind(this);
this.state = { this.state = {
sortBy: { sortBy: {
index: 1, index: 1,
@ -474,7 +482,7 @@ class RecordingList extends React.Component {
}; };
} }
onSort(_event, index, direction) { handleOnSort(_event, index, direction) {
this.setState({ this.setState({
sortBy: { sortBy: {
index, index,
@ -483,7 +491,7 @@ class RecordingList extends React.Component {
}); });
} }
rowClickHandler(_event, row) { handleRowClick(_event, row) {
cockpit.location.go([row.id], cockpit.location.options); cockpit.location.go([row.id], cockpit.location.options);
} }
@ -492,7 +500,7 @@ class RecordingList extends React.Component {
const { index, direction } = sortBy; const { index, direction } = sortBy;
// generate columns // generate columns
let titles = ["User", "Start", "End", "Duration"]; const titles = ["User", "Start", "End", "Duration"];
if (this.props.diff_hosts === true) if (this.props.diff_hosts === true)
titles.push("Hostname"); titles.push("Hostname");
const columnTitles = titles.map(title => ({ const columnTitles = titles.map(title => ({
@ -502,7 +510,7 @@ class RecordingList extends React.Component {
// sort rows // sort rows
let rows = this.props.list.map(rec => { let rows = this.props.list.map(rec => {
let cells = [ const cells = [
rec.user, rec.user,
formatDateTime(rec.start), formatDateTime(rec.start),
formatDateTime(rec.end), formatDateTime(rec.end),
@ -512,7 +520,7 @@ class RecordingList extends React.Component {
cells.push(rec.hostname); cells.push(rec.hostname);
return { return {
id: rec.id, id: rec.id,
cells: cells cells,
}; };
}).sort((a, b) => a.cells[index].localeCompare(b.cells[index])); }).sort((a, b) => a.cells[index].localeCompare(b.cells[index]));
rows = direction === SortByDirection.asc ? rows : rows.reverse(); rows = direction === SortByDirection.asc ? rows : rows.reverse();
@ -524,9 +532,10 @@ class RecordingList extends React.Component {
cells={columnTitles} cells={columnTitles}
rows={rows} rows={rows}
sortBy={sortBy} sortBy={sortBy}
onSort={this.onSort}> onSort={this.handleOnSort}
>
<TableHeader /> <TableHeader />
<TableBody onRowClick={this.rowClickHandler} /> <TableBody onRowClick={this.handleRowClick} />
</Table> </Table>
{!rows.length && {!rows.length &&
<EmptyState variant={EmptyStateVariant.small}> <EmptyState variant={EmptyStateVariant.small}>
@ -554,7 +563,7 @@ export default class View extends React.Component {
this.onLocationChanged = this.onLocationChanged.bind(this); this.onLocationChanged = this.onLocationChanged.bind(this);
this.journalctlIngest = this.journalctlIngest.bind(this); this.journalctlIngest = this.journalctlIngest.bind(this);
this.handleInputChange = this.handleInputChange.bind(this); this.handleInputChange = this.handleInputChange.bind(this);
this.openConfig = this.openConfig.bind(this); this.handleOpenConfig = this.handleOpenConfig.bind(this);
/* Journalctl instance */ /* Journalctl instance */
this.journalctl = null; this.journalctl = null;
/* Recording ID journalctl instance is invoked with */ /* Recording ID journalctl instance is invoked with */
@ -645,7 +654,7 @@ export default class View extends React.Component {
} }
r = { r = {
id: id, id,
matchList: ["TLOG_REC=" + id], matchList: ["TLOG_REC=" + id],
user: e.TLOG_USER, user: e.TLOG_USER,
boot_id: e._BOOT_ID, boot_id: e._BOOT_ID,
@ -675,7 +684,7 @@ export default class View extends React.Component {
r.duration = r.end - r.start; r.duration = r.end - r.start;
/* Find the recording in the list */ /* Find the recording in the list */
for (j = recordingList.length - 1; for (j = recordingList.length - 1;
j >= 0 && recordingList[j] != r; j >= 0 && recordingList[j] !== r;
j--); j--);
/* If found */ /* If found */
if (j >= 0) { if (j >= 0) {
@ -691,7 +700,7 @@ export default class View extends React.Component {
} }
} }
this.setState({ recordingList: recordingList }); this.setState({ recordingList });
} }
/* /*
@ -784,7 +793,7 @@ export default class View extends React.Component {
cockpit.location.go([], $.extend(cockpit.location.options, state)); cockpit.location.go([], $.extend(cockpit.location.options, state));
} }
openConfig() { handleOpenConfig() {
cockpit.location.go("/config"); cockpit.location.go("/config");
} }
@ -841,7 +850,8 @@ export default class View extends React.Component {
<EmptyState variant={EmptyStateVariant.small}> <EmptyState variant={EmptyStateVariant.small}>
<EmptyStateIcon <EmptyStateIcon
icon={ExclamationCircleIcon} icon={ExclamationCircleIcon}
color={global_danger_color_200.value} /> color={global_danger_color_200.value}
/>
<Title headingLevel="h2" size="lg"> <Title headingLevel="h2" size="lg">
{_("Error")} {_("Error")}
</Title> </Title>
@ -862,7 +872,8 @@ export default class View extends React.Component {
placeholder={_("Filter since")} placeholder={_("Filter since")}
value={this.state.date_since} value={this.state.date_since}
type="search" type="search"
onChange={value => this.handleInputChange("date_since", value)} /> onChange={value => this.handleInputChange("date_since", value)}
/>
</ToolbarItem> </ToolbarItem>
</ToolbarGroup> </ToolbarGroup>
<ToolbarGroup> <ToolbarGroup>
@ -873,7 +884,8 @@ export default class View extends React.Component {
placeholder={_("Filter until")} placeholder={_("Filter until")}
value={this.state.date_until} value={this.state.date_until}
type="search" type="search"
onChange={value => this.handleInputChange("date_until", value)} /> onChange={value => this.handleInputChange("date_until", value)}
/>
</ToolbarItem> </ToolbarItem>
</ToolbarGroup> </ToolbarGroup>
<ToolbarGroup> <ToolbarGroup>
@ -884,7 +896,8 @@ export default class View extends React.Component {
placeholder={_("Filter by content")} placeholder={_("Filter by content")}
value={this.state.search} value={this.state.search}
type="search" type="search"
onChange={value => this.handleInputChange("search", value)} /> onChange={value => this.handleInputChange("search", value)}
/>
</ToolbarItem> </ToolbarItem>
</ToolbarGroup> </ToolbarGroup>
<ToolbarGroup> <ToolbarGroup>
@ -895,7 +908,8 @@ export default class View extends React.Component {
placeholder={_("Filter by username")} placeholder={_("Filter by username")}
value={this.state.username} value={this.state.username}
type="search" type="search"
onChange={value => this.handleInputChange("username", value)} /> onChange={value => this.handleInputChange("username", value)}
/>
</ToolbarItem> </ToolbarItem>
</ToolbarGroup> </ToolbarGroup>
{this.state.diff_hosts === true && {this.state.diff_hosts === true &&
@ -907,11 +921,12 @@ export default class View extends React.Component {
placeholder={_("Filter by hostname")} placeholder={_("Filter by hostname")}
value={this.state.hostname} value={this.state.hostname}
type="search" type="search"
onChange={value => this.handleInputChange("hostname", value)} /> onChange={value => this.handleInputChange("hostname", value)}
/>
</ToolbarItem> </ToolbarItem>
</ToolbarGroup>} </ToolbarGroup>}
<ToolbarItem> <ToolbarItem>
<Button id="btn-config" onClick={this.openConfig}> <Button id="btn-config" onClick={this.handleOpenConfig}>
<CogIcon /> <CogIcon />
</Button> </Button>
</ToolbarItem> </ToolbarItem>
@ -928,7 +943,8 @@ export default class View extends React.Component {
username={this.state.username} username={this.state.username}
hostname={this.state.hostname} hostname={this.state.hostname}
list={this.state.recordingList} list={this.state.recordingList}
diff_hosts={this.state.diff_hosts} /> diff_hosts={this.state.diff_hosts}
/>
</PageSection> </PageSection>
</Page> </Page>
); );
@ -936,7 +952,8 @@ export default class View extends React.Component {
return ( return (
<Recording <Recording
recording={this.recordingMap[this.state.recordingID]} recording={this.recordingMap[this.state.recordingID]}
search={this.state.search} /> search={this.state.search}
/>
); );
} }
} }