starter-kit/src/app.jsx
Cristopfer Luis Viana da Silva 7f3cb61940 fix: card hide funcionality
2024-02-05 16:09:56 -03:00

330 lines
16 KiB
JavaScript

/*
* This file is part of Cockpit.
*
* Copyright (C) 2017 Red Hat, Inc.
*
* Cockpit is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Cockpit is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/
import cockpit from 'cockpit';
import React from 'react';
import { Alert, Card, CardTitle, CardHeader, CardBody, CardExpandableContent, Checkbox, Button, Spinner, Flex, FlexItem } from '@patternfly/react-core';
import { FanIcon, ThermometerHalfIcon, ChargingStationIcon, CpuIcon, EyeSlashIcon } from '@patternfly/react-icons/dist/esm/icons/';
const _ = cockpit.gettext;
export class Application extends React.Component {
constructor() {
super();
this.state = { sensors: {}, intervalId: {}, alert: null, fahrenheitTemp: [], fahrenheitChecked: false, isShowBtnInstall: false, sensorArgumet: "-j", isShowLoading: false, isExpanded: {}, expandAllCards: false, isError: false, hidedCards: [] };
}
componentDidMount() {
const storageHidedCards = localStorage.getItem('hidedCards');
const hidedCards = storageHidedCards != null && storageHidedCards !== '' ? storageHidedCards.split(',') : [];
const intervalId = setInterval(() => {
if (!this.state.isShowBtnInstall && !this.state.isError)
this.loadSensors();
}, 1000);
this.setState({ intervalId, hidedCards });
}
componentWillUnmount() {
clearInterval(this.state.intervalId);
}
loadSensors = () => {
cockpit
.spawn(["sensors", this.state.sensorArgumet], { err: "message", superuser: "try" })
.done((sucess) => {
if (this.state.sensorArgumet === "-j") {
this.setState({ sensors: JSON.parse(sucess), isShowBtnInstall: false });
} else {
const sensorsJson = {};
sucess.split(/\n\s*\n/).forEach(raw => {
let sensorsGroupName = "";
let index = 0;
let sensorTitle = "";
raw.split(/\n\s*/).forEach(element => {
if (index === 0) {
sensorsGroupName = element;
sensorsJson[sensorsGroupName] = {};
}
if (index === 1) {
const adapter = element.split(":");
sensorsJson[sensorsGroupName][adapter[0]] = adapter[1].trim();
}
if (index >= 2) {
const sensor = element.trim().split(":");
if (sensor[1] === "") {
sensorTitle = element.split(":")[0];
sensorsJson[sensorsGroupName][sensorTitle] = {};
} else {
sensorsJson[sensorsGroupName][sensorTitle][sensor[0]] = parseFloat(sensor[1].trim());
}
}
index += 1;
});
});
this.setState({ sensors: sensorsJson, isShowBtnInstall: false });
}
})
.fail((err) => {
if (err.message === "not-found") {
this.setState({ isShowBtnInstall: true });
this.setAlert(_('lm-sensors not found, you want install it ?'), 'danger');
this.getLmSensorsInstallCmd(0);
return;
}
if (err.message === "sensors: invalid option -- 'j'") {
this.setState({ sensorArgumet: "-u" });
return;
}
if (err.message === "sensors: invalid option -- 'u'") {
this.setAlert(_("this version of lm-sensors don't suport output sensors data!"), 'danger');
this.setState({ isError: true });
return;
}
this.setAlert(err.message, 'warning');
clearInterval(this.state.intervalId);
});
};
setIcon = (name) => {
if (typeof name !== 'undefined') {
if (name.includes('fan')) {
return <FanIcon size='md' />;
}
if (name.includes('temp')) {
return <ThermometerHalfIcon size='md' />;
}
if (name.includes('in')) {
return <ChargingStationIcon size='md' />;
}
if (name.includes('cpu')) {
return <CpuIcon size='md' />;
}
}
return <></>;
};
adjustLabel = (label) => {
return label.replace(label.substring(0, label.indexOf('_')) + '_', '');
};
setAlert = (msg, variant) => {
this.setState({ alert: { msg, variant } });
};
handleChange = (checked, event) => {
this.setState({ fahrenheitChecked: checked });
if (checked) {
// this.setAlert(_('lm-sensors has a bug that converts all data to fahrenheit, including voltage, fans and etc.'), 'info');
this.setState({ fahrenheitTemp: ['-f'] });
} else {
this.setState({ fahrenheitTemp: [], alert: null });
}
};
handleChangeCards = (checked, event) => {
const isExpanded = this.state.isExpanded;
Object.keys(isExpanded).forEach((element) => {
isExpanded[element] = checked;
});
this.setState({ isExpanded, expandAllCards: checked });
};
lstPacktsManager = ["apk", "apt-get", "dnf", "zypper"];
installCmd = null;
getLmSensorsInstallCmd = async (index) => {
const cmd = this.lstPacktsManager[index];
await cockpit.spawn([cmd, "-v"])
.then((sucesso) => {
switch (cmd) {
case "apk":
this.installCmd = [cmd, "add", "--no-cache", "lm-sensors", "-y"];
break;
case "dnf":
this.installCmd = [cmd, "install", "lm_sensors", "-y"];
break;
case "zypper":
this.installCmd = [cmd, "install", "-y", "sensors"];
break;
case "apt-get":
default:
this.installCmd = [cmd, "install", "lm-sensors", "-y"];
}
})
.fail((e) => {
this.getLmSensorsInstallCmd(index + 1);
});
};
handleInstallSensors = async () => {
this.setState({ isShowLoading: true });
cockpit.spawn(this.installCmd, { err: "message", superuser: "require" })
.done((sucess) => {
this.setState({ isShowLoading: false, isShowBtnInstall: false, alert: null });
cockpit.spawn(["sensors-detect", "--auto"], { err: "message", superuser: "require" })
.done((sucess) => {
cockpit.spawn(["modprobe", "coretemp"], { err: "message", superuser: "require" });
cockpit.spawn(["modprobe", "i2c-i801"], { err: "message", superuser: "require" });
cockpit.spawn(["modprobe", "drivetemp"], { err: "message", superuser: "require" });
})
.fail((err) => {
this.setAlert(err.message, 'warning');
});
})
.fail((err) => {
this.setState({ isShowLoading: false, isShowBtnInstall: false });
this.setAlert(err.message, 'warning');
});
};
adjustValue = (name, value) => {
if (typeof name !== 'undefined') {
if (name.includes('temp')) {
return this.state.fahrenheitChecked
? parseFloat((value * 9 / 5) + 32).toFixed(1)
.toString()
.concat(' °F')
: parseFloat(value).toFixed(1)
.toString()
.concat(' °C');
}
if (name.includes('fan')) {
return value.toString().concat(' RPM');
}
}
return value;
};
handleOnExpand = (event, id) => {
const isExpanded = this.state.isExpanded;
isExpanded[id] = !isExpanded[id];
this.setState({ isExpanded });
};
hideCard(cardId) {
const hidedCards = this.state.hidedCards;
hidedCards.push(cardId);
localStorage.setItem('hidedCards', hidedCards);
this.setState({ hidedCards });
}
handleShowHidedCards() {
const hidedCards = [];
localStorage.setItem('hidedCards', hidedCards);
this.setState({ hidedCards });
}
render() {
const { sensors, alert, fahrenheitChecked, isShowBtnInstall, isShowLoading, isExpanded, expandAllCards, hidedCards } = this.state;
return (
<>
<Card>
<CardTitle>{_('Sensors')}</CardTitle>
<CardBody>
<Checkbox
label={_("Show temperature in Fahrenheit")}
isChecked={fahrenheitChecked}
onChange={this.handleChange}
id="fahrenheit-checkbox"
name="fahrenheit-checkbox"
/>
<Checkbox
label={_("Expand all cards")}
isChecked={expandAllCards}
onChange={this.handleChangeCards}
id="allcards-checkbox"
name="allcards-checkbox"
/>
<>
{isShowLoading ? <Spinner isSVG /> : <></>}
{alert != null ? <Alert variant={alert.variant}>{alert.msg}</Alert> : <></>}
{isShowBtnInstall ? <Button onClick={this.handleInstallSensors}>{_('Install')}</Button> : <></>}
{hidedCards.length > 0 ? <Button onClick={() => this.handleShowHidedCards()}>{_('Show hided cards')}</Button> : <></>}
</>
{sensors !== null
? Object.entries(sensors).map((key, keyIndex) => {
if (hidedCards.includes(key[0])) {
return ('');
}
return (
<Card key={key}>
<CardTitle>{key[0]}
<Button variant="plain" aria-label="Action" onClick={() => this.hideCard(key[0])}>
<EyeSlashIcon />
</Button>
</CardTitle>
<CardBody>
<CardTitle>{key[1].Adapter}</CardTitle>
<Flex key={key[1]}>
{Object.entries(key[1]).map((item, itemIndex) => {
if (itemIndex === 0) return "";
const chave = keyIndex.toString() + itemIndex.toString();
if (isExpanded[chave] === undefined) {
isExpanded[chave] = false;
}
if (hidedCards.includes(chave)) {
return ('');
}
return (
<FlexItem key={item} style={{ width: "15%" }}>
<Card key={item} id="expandable-card-icon" isExpanded={isExpanded[chave]}>
<CardHeader
style={{ justifyContent: 'normal' }}
onExpand={(e) => this.handleOnExpand(e, chave)}
toggleButtonProps={{
id: 'toggle-button2',
'aria-label': 'Patternfly Details',
'aria-expanded': isExpanded[chave]
}}
><CardTitle>{item[0]}</CardTitle>
<Button variant="plain" aria-label="Action" onClick={() => this.hideCard(chave)}>
<EyeSlashIcon />
</Button>
</CardHeader>
<CardTitle>{this.setIcon(Object.keys(item[1])[0])} {this.adjustValue(Object.keys(item[1])[0], Object.values(item[1])[0])}
</CardTitle>
<CardExpandableContent>
<CardBody>
{Object.entries(item[1]).map((sensors, index) => (
<span key={sensors}>{this.adjustLabel(sensors[0])}: {sensors[1]}<br /></span>
))}
</CardBody>
</CardExpandableContent>
</Card>
</FlexItem>
);
})}
</Flex>
</CardBody>
</Card>
);
}
)
: ''}
</CardBody>
</Card>
</>
);
}
}