/* * 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 . */ 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 ; } if (name.includes('temp')) { return ; } if (name.includes('in')) { return ; } if (name.includes('cpu')) { return ; } } 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 ( <> {_('Sensors')} <> {isShowLoading ? : <>} {alert != null ? {alert.msg} : <>} {isShowBtnInstall ? : <>} {hidedCards.length > 0 ? : <>} {sensors !== null ? Object.entries(sensors).map((key, keyIndex) => { if (hidedCards.includes(key[0])) { return (''); } return ( {key[0]} {key[1].Adapter} {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 ( this.handleOnExpand(e, chave)} toggleButtonProps={{ id: 'toggle-button2', 'aria-label': 'Patternfly Details', 'aria-expanded': isExpanded[chave] }} >{item[0]} {this.setIcon(Object.keys(item[1])[0])} {this.adjustValue(Object.keys(item[1])[0], Object.values(item[1])[0])} {Object.entries(item[1]).map((sensors, index) => ( {this.adjustLabel(sensors[0])}: {sensors[1]}
))}
); })}
); } ) : ''}
); } }