├── .cirrus.yml ├── .eslintignore ├── .eslintrc.json ├── .flake8 ├── .fmf └── version ├── .github ├── dependabot.yml └── workflows │ ├── cockpit-lib-update.yml │ └── release.yml ├── .gitignore ├── .stylelintrc.json ├── LICENSE ├── Makefile ├── README.md ├── build.js ├── org.cockpit-project.sensors.metainfo.xml ├── package.json ├── packaging ├── cockpit-sensors.control └── cockpit-sensors.spec.in ├── packit.yaml ├── plans └── all.fmf ├── po ├── de.po └── pt_BR.po ├── pyproject.toml ├── src ├── app.jsx ├── app.scss ├── index.html ├── index.js └── manifest.json └── test ├── browser ├── browser.sh ├── main.fmf └── run-test.sh ├── check-application ├── reference-image ├── run └── vm.install /.cirrus.yml: -------------------------------------------------------------------------------- 1 | container: 2 | # official cockpit CI container, with cockpit related build and test dependencies 3 | # if you want to use your own, see the documentation about required packages: 4 | # https://github.com/cockpit-project/cockpit/blob/main/HACKING.md#getting-the-development-dependencies 5 | image: quay.io/cockpit/tasks 6 | kvm: true 7 | # increase this if you have many tests that benefit from parallelism 8 | cpu: 1 9 | 10 | test_task: 11 | env: 12 | matrix: 13 | - TEST_OS: fedora-39 14 | - TEST_OS: centos-8-stream 15 | 16 | fix_kvm_script: sudo chmod 666 /dev/kvm 17 | 18 | # test PO template generation 19 | pot_build_script: make po/sensors.pot 20 | 21 | # chromium has too little /dev/shm, and we can't make that bigger 22 | check_script: TEST_BROWSER=firefox TEST_JOBS=$(nproc) TEST_OS=$TEST_OS make check 23 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | pkg/lib/* 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "es6": true 6 | }, 7 | "extends": ["eslint:recommended", "standard", "standard-jsx", "standard-react"], 8 | "parserOptions": { 9 | "ecmaVersion": "2022", 10 | "sourceType": "module" 11 | }, 12 | "plugins": ["react", "react-hooks"], 13 | "rules": { 14 | "indent": ["error", 4, 15 | { 16 | "ObjectExpression": "first", 17 | "CallExpression": {"arguments": "first"}, 18 | "MemberExpression": 2, 19 | "ignoredNodes": [ "JSXAttribute" ] 20 | }], 21 | "newline-per-chained-call": ["error", { "ignoreChainWithDepth": 2 }], 22 | "no-var": "error", 23 | "lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }], 24 | "prefer-promise-reject-errors": ["error", { "allowEmptyReject": true }], 25 | "react/jsx-indent": ["error", 4], 26 | "semi": ["error", "always", { "omitLastInOneLineBlock": true }], 27 | 28 | "react-hooks/rules-of-hooks": "error", 29 | "react-hooks/exhaustive-deps": "error", 30 | 31 | "camelcase": "off", 32 | "comma-dangle": "off", 33 | "curly": "off", 34 | "jsx-quotes": "off", 35 | "key-spacing": "off", 36 | "no-console": "off", 37 | "quotes": "off", 38 | "react/jsx-curly-spacing": "off", 39 | "react/jsx-indent-props": "off", 40 | "react/prop-types": "off", 41 | "space-before-function-paren": "off", 42 | "standard/no-callback-literal": "off" 43 | }, 44 | "globals": { 45 | "require": false, 46 | "module": false 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 118 3 | -------------------------------------------------------------------------------- /.fmf/version: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | # run these when most of our developers don't work, don't DoS our CI over the day 8 | time: "22:00" 9 | timezone: "Europe/Berlin" 10 | open-pull-requests-limit: 3 11 | groups: 12 | eslint: 13 | patterns: 14 | - "eslint*" 15 | esbuild: 16 | patterns: 17 | - "esbuild*" 18 | stylelint: 19 | patterns: 20 | - "stylelint*" 21 | patternfly: 22 | patterns: 23 | - "@patternfly*" 24 | 25 | - package-ecosystem: "github-actions" 26 | directory: "/" 27 | open-pull-requests-limit: 3 28 | labels: 29 | - "no-test" 30 | schedule: 31 | interval: "weekly" 32 | -------------------------------------------------------------------------------- /.github/workflows/cockpit-lib-update.yml: -------------------------------------------------------------------------------- 1 | name: cockpit-lib-update 2 | on: 3 | schedule: 4 | - cron: '0 2 * * 4' 5 | # can be run manually on https://github.com/cockpit-project/starter-kit/actions 6 | workflow_dispatch: 7 | jobs: 8 | cockpit-lib-update: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | pull-requests: write 12 | contents: write 13 | steps: 14 | - name: Set up dependencies 15 | run: | 16 | sudo apt update 17 | sudo apt install -y make 18 | 19 | - name: Set up configuration and secrets 20 | run: | 21 | printf '[user]\n\tname = Cockpit Project\n\temail=cockpituous@gmail.com\n' > ~/.gitconfig 22 | echo '${{ secrets.GITHUB_TOKEN }}' > ~/.config/github-token 23 | 24 | - name: Clone repository 25 | uses: actions/checkout@v4 26 | 27 | - name: Run cockpit-lib-update 28 | run: | 29 | make bots 30 | bots/cockpit-lib-update 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Create a GitHub upstream release. Replace "TARNAME" with your project tarball 2 | # name and enable this by dropping the ".disabled" suffix from the file name. 3 | # See README.md. 4 | name: release 5 | on: 6 | push: 7 | tags: 8 | # this is a glob, not a regexp 9 | - "*" 10 | jobs: 11 | source: 12 | runs-on: ubuntu-latest 13 | container: 14 | image: quay.io/cockpit/tasks:latest 15 | options: --user root 16 | permissions: 17 | # create GitHub release 18 | contents: write 19 | steps: 20 | - name: Clone repository 21 | uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 0 24 | 25 | # https://github.blog/2022-04-12-git-security-vulnerability-announced/ 26 | - name: Pacify git's permission check 27 | run: git config --global --add safe.directory /__w/cockpit-sensors/cockpit-sensors 28 | 29 | - name: Workaround for https://github.com/actions/checkout/pull/697 30 | run: git fetch --force origin $(git describe --tags):refs/tags/$(git describe --tags) 31 | 32 | - name: Build release 33 | run: make dist 34 | 35 | - name: Build Deb release 36 | run: make deb 37 | 38 | - name: Upload binaries to release 39 | uses: svenstaro/upload-release-action@v2 40 | with: 41 | repo_token: ${{ secrets.GITHUB_TOKEN }} 42 | file: cockpit-sensors.tar.xz 43 | asset_name: cockpit-sensors.tar.xz 44 | tag: ${{ github.ref }} 45 | 46 | - name: Upload Deb binaries to release 47 | uses: svenstaro/upload-release-action@v2 48 | with: 49 | repo_token: ${{ secrets.GITHUB_TOKEN }} 50 | file: cockpit-sensors.deb 51 | asset_name: cockpit-sensors.deb 52 | tag: ${{ github.ref }} 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Please keep this file sorted (LC_COLLATE=C.UTF-8), 2 | # grouped into the 3 categories below: 3 | # - general patterns (match in all directories) 4 | # - patterns to match files at the toplevel 5 | # - patterns to match files in subdirs 6 | 7 | # general patterns 8 | *.pyc 9 | *.rpm 10 | 11 | # toplevel (/...) 12 | /Test*.html 13 | /Test*.json 14 | /Test*.log 15 | /Test*.log.gz 16 | /Test*.png 17 | /*.whl 18 | /bots 19 | /cockpit-*.tar.xz 20 | /cockpit-navigator.spec 21 | /dist/ 22 | /package-lock.json 23 | /pkg/ 24 | /node_modules/ 25 | /tmp/ 26 | /tools/ 27 | 28 | # subdirs (/subdir/...) 29 | /packaging/arch/PKGBUILD 30 | /packaging/debian/changelog 31 | /po/*.pot 32 | /po/LINGUAS 33 | /test/common/ 34 | /test/images/ 35 | /test/static-code 36 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard-scss", 3 | "rules": { 4 | "at-rule-empty-line-before": null, 5 | "declaration-empty-line-before": null, 6 | "custom-property-empty-line-before": null, 7 | "comment-empty-line-before": null, 8 | "scss/double-slash-comment-empty-line-before": null, 9 | "scss/dollar-variable-colon-space-after": null, 10 | 11 | "custom-property-pattern": null, 12 | "declaration-block-no-duplicate-properties": null, 13 | "declaration-block-no-redundant-longhand-properties": null, 14 | "declaration-block-no-shorthand-property-overrides": null, 15 | "declaration-block-single-line-max-declarations": null, 16 | "font-family-no-duplicate-names": null, 17 | "function-url-quotes": null, 18 | "keyframes-name-pattern": null, 19 | "no-descending-specificity": null, 20 | "no-duplicate-selectors": null, 21 | "scss/at-extend-no-missing-placeholder": null, 22 | "scss/at-import-partial-extension": null, 23 | "scss/at-import-no-partial-leading-underscore": null, 24 | "scss/load-no-partial-leading-underscore": true, 25 | "scss/at-mixin-pattern": null, 26 | "scss/comment-no-empty": null, 27 | "scss/dollar-variable-pattern": null, 28 | "scss/double-slash-comment-whitespace-inside": null, 29 | "scss/no-global-function-names": null, 30 | "scss/operator-no-unspaced": null, 31 | "selector-class-pattern": null, 32 | "selector-id-pattern": null 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # extract name from package.json 2 | PACKAGE_NAME := $(shell awk '/"name":/ {gsub(/[",]/, "", $$2); print $$2}' package.json) 3 | RPM_NAME := cockpit-$(PACKAGE_NAME) 4 | VERSION := $(shell T=$$(git describe 2>/dev/null) || T=1; echo $$T | tr '-' '.') 5 | ifeq ($(TEST_OS),) 6 | TEST_OS = centos-8-stream 7 | endif 8 | export TEST_OS 9 | TARFILE=$(RPM_NAME).tar.xz 10 | NODE_CACHE=$(RPM_NAME)-node.tar.xz 11 | SPEC=$(RPM_NAME).spec 12 | PREFIX ?= /usr/local 13 | APPSTREAMFILE=org.cockpit-project.$(PACKAGE_NAME).metainfo.xml 14 | VM_IMAGE=$(CURDIR)/test/images/$(TEST_OS) 15 | # stamp file to check for node_modules/ 16 | NODE_MODULES_TEST=package-lock.json 17 | # one example file in dist/ from bundler to check if that already ran 18 | DIST_TEST=dist/manifest.json 19 | # one example file in pkg/lib to check if it was already checked out 20 | COCKPIT_REPO_STAMP=pkg/lib/cockpit-po-plugin.js 21 | # common arguments for tar, mostly to make the generated tarballs reproducible 22 | TAR_ARGS = --sort=name --mtime "@$(shell git show --no-patch --format='%at')" --mode=go=rX,u+rw,a-s --numeric-owner --owner=0 --group=0 23 | 24 | all: $(DIST_TEST) 25 | 26 | # checkout common files from Cockpit repository required to build this project; 27 | # this has no API stability guarantee, so check out a stable tag when you start 28 | # a new project, use the latest release, and update it from time to time 29 | COCKPIT_REPO_FILES = \ 30 | pkg/lib \ 31 | test/common \ 32 | test/static-code \ 33 | $(NULL) 34 | 35 | COCKPIT_REPO_URL = https://github.com/cockpit-project/cockpit.git 36 | COCKPIT_REPO_COMMIT = e46f7e022e13f2a984d25a3e189a5117bd1fe88a # 318 37 | 38 | 39 | $(COCKPIT_REPO_FILES): $(COCKPIT_REPO_STAMP) 40 | COCKPIT_REPO_TREE = '$(strip $(COCKPIT_REPO_COMMIT))^{tree}' 41 | $(COCKPIT_REPO_STAMP): Makefile 42 | @git rev-list --quiet --objects $(COCKPIT_REPO_TREE) -- 2>/dev/null || \ 43 | git fetch --no-tags --no-write-fetch-head --depth=1 $(COCKPIT_REPO_URL) $(COCKPIT_REPO_COMMIT) 44 | git archive $(COCKPIT_REPO_TREE) -- $(COCKPIT_REPO_FILES) | tar x 45 | 46 | # 47 | # i18n 48 | # 49 | 50 | LINGUAS=$(basename $(notdir $(wildcard po/*.po))) 51 | 52 | po/$(PACKAGE_NAME).js.pot: 53 | xgettext --default-domain=$(PACKAGE_NAME) --output=$@ --language=C --keyword= \ 54 | --add-comments=Translators: \ 55 | --keyword=_:1,1t --keyword=_:1c,2,2t --keyword=C_:1c,2 \ 56 | --keyword=N_ --keyword=NC_:1c,2 \ 57 | --keyword=gettext:1,1t --keyword=gettext:1c,2,2t \ 58 | --keyword=ngettext:1,2,3t --keyword=ngettext:1c,2,3,4t \ 59 | --keyword=gettextCatalog.getString:1,3c --keyword=gettextCatalog.getPlural:2,3,4c \ 60 | --from-code=UTF-8 $$(find src/ -name '*.js' -o -name '*.jsx') 61 | 62 | po/$(PACKAGE_NAME).html.pot: $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP) 63 | pkg/lib/html2po.js -o $@ $$(find src -name '*.html') 64 | 65 | po/$(PACKAGE_NAME).manifest.pot: $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP) 66 | pkg/lib/manifest2po.js src/manifest.json -o $@ 67 | 68 | po/$(PACKAGE_NAME).metainfo.pot: $(APPSTREAMFILE) 69 | xgettext --default-domain=$(PACKAGE_NAME) --output=$@ $< 70 | 71 | po/$(PACKAGE_NAME).pot: po/$(PACKAGE_NAME).html.pot po/$(PACKAGE_NAME).js.pot po/$(PACKAGE_NAME).manifest.pot po/$(PACKAGE_NAME).metainfo.pot 72 | msgcat --sort-output --output-file=$@ $^ 73 | 74 | po/LINGUAS: 75 | echo $(LINGUAS) | tr ' ' '\n' > $@ 76 | 77 | # 78 | # Build/Install/dist 79 | # 80 | 81 | $(SPEC): packaging/$(SPEC).in $(NODE_MODULES_TEST) 82 | provides=$$(npm ls --omit dev --package-lock-only --depth=Infinity | grep -Eo '[^[:space:]]+@[^[:space:]]+' | sort -u | sed 's/^/Provides: bundled(npm(/; s/\(.*\)@/\1)) = /'); \ 83 | awk -v p="$$provides" '{gsub(/%{VERSION}/, "$(VERSION)"); gsub(/%{NPM_PROVIDES}/, p)}1' $< > $@ 84 | 85 | $(DIST_TEST): $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP) $(shell find src/ -type f) package.json build.js 86 | NODE_ENV=$(NODE_ENV) ./build.js 87 | 88 | watch: $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP) 89 | NODE_ENV=$(NODE_ENV) ./build.js --watch 90 | 91 | clean: 92 | rm -rf dist/ 93 | rm -f $(SPEC) 94 | rm -f po/LINGUAS 95 | 96 | install: $(DIST_TEST) po/LINGUAS 97 | mkdir -p $(DESTDIR)$(PREFIX)/share/cockpit/$(PACKAGE_NAME) 98 | cp -r dist/* $(DESTDIR)$(PREFIX)/share/cockpit/$(PACKAGE_NAME) 99 | mkdir -p $(DESTDIR)$(PREFIX)/share/metainfo/ 100 | msgfmt --xml -d po \ 101 | --template $(APPSTREAMFILE) \ 102 | -o $(DESTDIR)$(PREFIX)/share/metainfo/$(APPSTREAMFILE) 103 | 104 | # this requires a built source tree and avoids having to install anything system-wide 105 | devel-install: $(DIST_TEST) 106 | mkdir -p ~/.local/share/cockpit 107 | ln -s `pwd`/dist ~/.local/share/cockpit/$(PACKAGE_NAME) 108 | 109 | # assumes that there was symlink set up using the above devel-install target, 110 | # and removes it 111 | devel-uninstall: 112 | rm -f ~/.local/share/cockpit/$(PACKAGE_NAME) 113 | 114 | print-version: 115 | @echo "$(VERSION)" 116 | 117 | dist: $(TARFILE) 118 | @ls -1 $(TARFILE) 119 | 120 | # when building a distribution tarball, call bundler with a 'production' environment 121 | # we don't ship node_modules for license and compactness reasons; we ship a 122 | # pre-built dist/ (so it's not necessary) and ship package-lock.json (so that 123 | # node_modules/ can be reconstructed if necessary) 124 | $(TARFILE): export NODE_ENV=production 125 | $(TARFILE): $(DIST_TEST) $(SPEC) 126 | if type appstream-util >/dev/null 2>&1; then appstream-util validate-relax --nonet *.metainfo.xml; fi 127 | tar --xz $(TAR_ARGS) -cf $(TARFILE) --transform 's,^,$(RPM_NAME)/,' \ 128 | --exclude packaging/$(SPEC).in --exclude node_modules \ 129 | $$(git ls-files) $(COCKPIT_REPO_FILES) $(NODE_MODULES_TEST) $(SPEC) dist/ 130 | 131 | $(NODE_CACHE): $(NODE_MODULES_TEST) 132 | tar --xz $(TAR_ARGS) -cf $@ node_modules 133 | 134 | node-cache: $(NODE_CACHE) 135 | 136 | # convenience target for developers 137 | srpm: $(TARFILE) $(NODE_CACHE) $(SPEC) 138 | rpmbuild -bs \ 139 | --define "_sourcedir `pwd`" \ 140 | --define "_srcrpmdir `pwd`" \ 141 | $(SPEC) 142 | 143 | # convenience target for developers 144 | rpm: $(TARFILE) $(NODE_CACHE) $(SPEC) 145 | mkdir -p "`pwd`/output" 146 | mkdir -p "`pwd`/rpmbuild" 147 | rpmbuild -bb \ 148 | --define "_sourcedir `pwd`" \ 149 | --define "_specdir `pwd`" \ 150 | --define "_builddir `pwd`/rpmbuild" \ 151 | --define "_srcrpmdir `pwd`" \ 152 | --define "_rpmdir `pwd`/output" \ 153 | --define "_buildrootdir `pwd`/build" \ 154 | $(SPEC) 155 | find `pwd`/output -name '*.rpm' -printf '%f\n' -exec mv {} . \; 156 | rm -r "`pwd`/rpmbuild" 157 | rm -r "`pwd`/output" "`pwd`/build" 158 | 159 | # build a VM with locally built distro pkgs installed 160 | # disable networking, VM images have mock/pbuilder with the common build dependencies pre-installed 161 | $(VM_IMAGE): $(TARFILE) $(NODE_CACHE) bots test/vm.install 162 | bots/image-customize --no-network --fresh \ 163 | --upload $(NODE_CACHE):/var/tmp/ --build $(TARFILE) \ 164 | --script $(CURDIR)/test/vm.install $(TEST_OS) 165 | 166 | # convenience target for the above 167 | vm: $(VM_IMAGE) 168 | @echo $(VM_IMAGE) 169 | 170 | # convenience target to print the filename of the test image 171 | print-vm: 172 | @echo $(VM_IMAGE) 173 | 174 | # convenience target to setup all the bits needed for the integration tests 175 | # without actually running them 176 | prepare-check: $(NODE_MODULES_TEST) $(VM_IMAGE) test/common 177 | 178 | # run the browser integration tests 179 | # this will run all tests/check-* and format them as TAP 180 | check: prepare-check 181 | test/common/run-tests ${RUN_TESTS_OPTIONS} 182 | 183 | codecheck: test/static-code $(NODE_MODULES_TEST) 184 | test/static-code 185 | 186 | # checkout Cockpit's bots for standard test VM images and API to launch them 187 | bots: $(COCKPIT_REPO_STAMP) 188 | test/common/make-bots 189 | 190 | $(NODE_MODULES_TEST): package.json 191 | # if it exists already, npm install won't update it; force that so that we always get up-to-date packages 192 | rm -f package-lock.json 193 | # unset NODE_ENV, skips devDependencies otherwise 194 | env -u NODE_ENV npm install --ignore-scripts 195 | env -u NODE_ENV npm prune 196 | 197 | .PHONY: all clean install devel-install devel-uninstall print-version dist node-cache rpm prepare-check check vm print-vm 198 | 199 | 200 | deb: 201 | rm -fr "`pwd`/output" 202 | mkdir -m 0755 -p "`pwd`/output" 203 | mkdir -m 0755 -p "`pwd`/output/cockpit-$(PACKAGE_NAME)" 204 | mkdir -m 0755 -p "`pwd`/output/cockpit-$(PACKAGE_NAME)/DEBIAN" 205 | mkdir -m 0755 -p "`pwd`/output/cockpit-$(PACKAGE_NAME)/usr/share/cockpit/$(PACKAGE_NAME)" 206 | cp -r dist/* "`pwd`/output/cockpit-$(PACKAGE_NAME)/usr/share/cockpit/$(PACKAGE_NAME)" 207 | cp packaging/cockpit-$(PACKAGE_NAME).control "`pwd`/output/cockpit-$(PACKAGE_NAME)/DEBIAN/control" 208 | chmod 755 "`pwd`/output/cockpit-$(PACKAGE_NAME)/DEBIAN/control" 209 | dpkg-deb -Zxz --build output/cockpit-$(PACKAGE_NAME) 210 | mv "`pwd`/output/cockpit-$(PACKAGE_NAME).deb" "`pwd`/" 211 | rm -r "`pwd`/output" 212 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cockpit Sensors 2 | 3 | module that displays all data reported by lm-sensors 4 | 5 | # Usage 6 | 7 | - Download the lastest [Sensors release](https://github.com/ocristopfer/cockpit-sensors/releases) 8 | - Extract the content of dist folder to /usr/share/cockpit/sensors 9 | - Check if Sensors tools is show on menu 10 | 11 | - Installation script provided by [@subz390](https://github.com/subz390): 12 | 13 | ```shell 14 | wget https://github.com/ocristopfer/cockpit-sensors/releases/latest/download/cockpit-sensors.tar.xz && \ 15 | tar -xf cockpit-sensors.tar.xz cockpit-sensors/dist && \ 16 | mv cockpit-sensors/dist /usr/share/cockpit/sensors && \ 17 | rm -r cockpit-sensors && \ 18 | rm cockpit-sensors.tar.xz 19 | ``` 20 | 21 | - .deb package: 22 | [cockpit-sensors.deb](https://github.com/ocristopfer/cockpit-sensors/releases/latest/download/cockpit-sensors.deb) 23 | 24 | - .rpm package: 25 | [cockpit-sensors.noarch.rpm](https://github.com/ocristopfer/cockpit-sensors/releases/latest/download/cockpit-sensors.noarch.rpm) 26 | 27 | # Prints 28 | 29 | ![alt text](https://i.ibb.co/tQ22dF4/cockpit.png) 30 | 31 | # Module created using Starter Kit 32 | 33 | # Cockpit Starter Kit 34 | 35 | Scaffolding for a [Cockpit](https://cockpit-project.org/) module. 36 | 37 | # Development dependencies 38 | 39 | On Debian/Ubuntu: 40 | 41 | $ sudo apt install gettext nodejs npm make 42 | 43 | On Fedora: 44 | 45 | $ sudo dnf install gettext nodejs npm make 46 | 47 | # Getting and building the source 48 | 49 | These commands check out the source and build it into the `dist/` directory: 50 | 51 | ``` 52 | git clone https://github.com/cockpit-project/starter-kit.git 53 | cd starter-kit 54 | make 55 | ``` 56 | 57 | # Installing 58 | 59 | `make install` compiles and installs the package in `/usr/local/share/cockpit/`. The 60 | convenience targets `srpm` and `rpm` build the source and binary rpms, 61 | respectively. Both of these make use of the `dist` target, which is used 62 | to generate the distribution tarball. In `production` mode, source files are 63 | automatically minified and compressed. Set `NODE_ENV=production` if you want to 64 | duplicate this behavior. 65 | 66 | For development, you usually want to run your module straight out of the git 67 | tree. To do that, run `make devel-install`, which links your checkout to the 68 | location were cockpit-bridge looks for packages. If you prefer to do 69 | this manually: 70 | 71 | ``` 72 | mkdir -p ~/.local/share/cockpit 73 | ln -s `pwd`/dist ~/.local/share/cockpit/starter-kit 74 | ``` 75 | 76 | After changing the code and running `make` again, reload the Cockpit page in 77 | your browser. 78 | 79 | You can also use 80 | [watch mode](https://esbuild.github.io/api/#watch) to 81 | automatically update the bundle on every code change with 82 | 83 | $ ./build.js -w 84 | 85 | or 86 | 87 | $ make watch 88 | 89 | When developing against a virtual machine, watch mode can also automatically upload 90 | the code changes by setting the `RSYNC` environment variable to 91 | the remote hostname. 92 | 93 | $ RSYNC=c make watch 94 | 95 | When developing against a remote host as a normal user, `RSYNC_DEVEL` can be 96 | set to upload code changes to `~/.local/share/cockpit/` instead of 97 | `/usr/local`. 98 | 99 | $ RSYNC_DEVEL=example.com make watch 100 | 101 | To "uninstall" the locally installed version, run `make devel-uninstall`, or 102 | remove manually the symlink: 103 | 104 | rm ~/.local/share/cockpit/starter-kit 105 | 106 | # Running eslint 107 | 108 | Cockpit Starter Kit uses [ESLint](https://eslint.org/) to automatically check 109 | JavaScript code style in `.js` and `.jsx` files. 110 | 111 | eslint is executed as part of `test/static-code`, aka. `make codecheck`. 112 | 113 | For developer convenience, the ESLint can be started explicitly by: 114 | 115 | $ npm run eslint 116 | 117 | Violations of some rules can be fixed automatically by: 118 | 119 | $ npm run eslint:fix 120 | 121 | Rules configuration can be found in the `.eslintrc.json` file. 122 | 123 | ## Running stylelint 124 | 125 | Cockpit uses [Stylelint](https://stylelint.io/) to automatically check CSS code 126 | style in `.css` and `scss` files. 127 | 128 | styleint is executed as part of `test/static-code`, aka. `make codecheck`. 129 | 130 | For developer convenience, the Stylelint can be started explicitly by: 131 | 132 | $ npm run stylelint 133 | 134 | Violations of some rules can be fixed automatically by: 135 | 136 | $ npm run stylelint:fix 137 | 138 | Rules configuration can be found in the `.stylelintrc.json` file. 139 | 140 | # Running tests locally 141 | 142 | Run `make check` to build an RPM, install it into a standard Cockpit test VM 143 | (centos-8-stream by default), and run the test/check-application integration test on 144 | it. This uses Cockpit's Chrome DevTools Protocol based browser tests, through a 145 | Python API abstraction. Note that this API is not guaranteed to be stable, so 146 | if you run into failures and don't want to adjust tests, consider checking out 147 | Cockpit's test/common from a tag instead of main (see the `test/common` 148 | target in `Makefile`). 149 | 150 | After the test VM is prepared, you can manually run the test without rebuilding 151 | the VM, possibly with extra options for tracing and halting on test failures 152 | (for interactive debugging): 153 | 154 | TEST_OS=centos-8-stream test/check-application -tvs 155 | 156 | It is possible to setup the test environment without running the tests: 157 | 158 | TEST_OS=centos-8-stream make prepare-check 159 | 160 | You can also run the test against a different Cockpit image, for example: 161 | 162 | TEST_OS=fedora-34 make check 163 | 164 | # Running tests in CI 165 | 166 | These tests can be run in [Cirrus CI](https://cirrus-ci.org/), on their free 167 | [Linux Containers](https://cirrus-ci.org/guide/linux/) environment which 168 | explicitly supports `/dev/kvm`. Please see [Quick 169 | Start](https://cirrus-ci.org/guide/quick-start/) how to set up Cirrus CI for 170 | your project after forking from starter-kit. 171 | 172 | The included [.cirrus.yml](./.cirrus.yml) runs the integration tests for two 173 | operating systems (Fedora and CentOS 8). Note that if/once your project grows 174 | bigger, or gets frequent changes, you may need to move to a paid account, or 175 | different infrastructure with more capacity. 176 | 177 | Tests also run in [Packit](https://packit.dev/) for all currently supported 178 | Fedora releases; see the [packit.yaml](./packit.yaml) control file. You need to 179 | [enable Packit-as-a-service](https://packit.dev/docs/packit-service/) in your GitHub project to use this. 180 | To run the tests in the exact same way for upstream pull requests and for 181 | [Fedora package update gating](https://docs.fedoraproject.org/en-US/ci/), the 182 | tests are wrapped in the [FMF metadata format](https://github.com/teemtee/fmf) 183 | for using with the [tmt test management tool](https://docs.fedoraproject.org/en-US/ci/tmt/). 184 | Note that Packit tests can _not_ run their own virtual machine images, thus 185 | they only run [@nondestructive tests](https://github.com/cockpit-project/cockpit/blob/main/test/common/testlib.py). 186 | 187 | # Customizing 188 | 189 | After cloning the Starter Kit you should rename the files, package names, and 190 | labels to your own project's name. Use these commands to find out what to 191 | change: 192 | 193 | find -iname '*starter*' 194 | git grep -i starter 195 | 196 | # Automated release 197 | 198 | Once your cloned project is ready for a release, you should consider automating 199 | that. The intention is that the only manual step for releasing a project is to create 200 | a signed tag for the version number, which includes a summary of the noteworthy 201 | changes: 202 | 203 | ``` 204 | 123 205 | 206 | - this new feature 207 | - fix bug #123 208 | ``` 209 | 210 | Pushing the release tag triggers the [release.yml](.github/workflows/release.yml.disabled) 211 | [GitHub action](https://github.com/features/actions) workflow. This creates the 212 | official release tarball and publishes as upstream release to GitHub. The 213 | workflow is disabled by default -- to use it, edit the file as per the comment 214 | at the top, and rename it to just `*.yml`. 215 | 216 | The Fedora and COPR releases are done with [Packit](https://packit.dev/), 217 | see the [packit.yaml](./packit.yaml) control file. 218 | 219 | # Automated maintenance 220 | 221 | It is important to keep your [NPM modules](./package.json) up to date, to keep 222 | up with security updates and bug fixes. This is done with the 223 | [npm-update bot script](https://github.com/cockpit-project/bots/blob/main/npm-update) 224 | which is run weekly or upon [manual request](https://github.com/cockpit-project/starter-kit/actions) through the 225 | [npm-update.yml](.github/workflows/npm-update.yml) [GitHub action](https://github.com/features/actions). 226 | 227 | # Further reading 228 | 229 | - The [Starter Kit announcement](https://cockpit-project.org/blog/cockpit-starter-kit.html) 230 | blog post explains the rationale for this project. 231 | - [Cockpit Deployment and Developer documentation](https://cockpit-project.org/guide/latest/) 232 | - [Make your project easily discoverable](https://cockpit-project.org/blog/making-a-cockpit-application.html) 233 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import fs from 'node:fs'; 4 | import path from 'node:path'; 5 | import os from 'node:os'; 6 | 7 | import copy from 'esbuild-plugin-copy'; 8 | 9 | import { cleanPlugin } from './pkg/lib/esbuild-cleanup-plugin.js'; 10 | import { cockpitCompressPlugin } from './pkg/lib/esbuild-compress-plugin.js'; 11 | import { cockpitPoEsbuildPlugin } from './pkg/lib/cockpit-po-plugin.js'; 12 | import { cockpitRsyncEsbuildPlugin } from './pkg/lib/cockpit-rsync-plugin.js'; 13 | import { esbuildStylesPlugins } from './pkg/lib/esbuild-common.js'; 14 | 15 | const production = process.env.NODE_ENV === 'production'; 16 | const useWasm = os.arch() !== 'x64'; 17 | const esbuild = (await import(useWasm ? 'esbuild-wasm' : 'esbuild')).default; 18 | 19 | const parser = (await import('argparse')).default.ArgumentParser(); 20 | parser.add_argument('-r', '--rsync', { help: "rsync bundles to ssh target after build", metavar: "HOST" }); 21 | parser.add_argument('-w', '--watch', { action: 'store_true', help: "Enable watch mode", default: process.env.ESBUILD_WATCH === "true" }); 22 | const args = parser.parse_args(); 23 | 24 | if (args.rsync) 25 | process.env.RSYNC = args.rsync; 26 | 27 | // List of directories to use when using import statements 28 | const nodePaths = ['pkg/lib']; 29 | const outdir = 'dist'; 30 | 31 | // Obtain package name from package.json 32 | const packageJson = JSON.parse(fs.readFileSync('package.json')); 33 | 34 | function notifyEndPlugin() { 35 | return { 36 | name: 'notify-end', 37 | setup(build) { 38 | let startTime; 39 | 40 | build.onStart(() => { 41 | startTime = new Date(); 42 | }); 43 | 44 | build.onEnd(() => { 45 | const endTime = new Date(); 46 | const timeStamp = endTime.toTimeString().split(' ')[0]; 47 | console.log(`${timeStamp}: Build finished in ${endTime - startTime} ms`); 48 | }); 49 | } 50 | }; 51 | } 52 | 53 | // similar to fs.watch(), but recursively watches all subdirectories 54 | function watch_dirs(dir, on_change) { 55 | const callback = (ev, dir, fname) => { 56 | // only listen for "change" events, as renames are noisy 57 | // ignore hidden files 58 | const isHidden = /^\./.test(fname); 59 | if (ev !== "change" || isHidden) { 60 | return; 61 | } 62 | on_change(path.join(dir, fname)); 63 | }; 64 | 65 | fs.watch(dir, {}, (ev, path) => callback(ev, dir, path)); 66 | 67 | // watch all subdirectories in dir 68 | const d = fs.opendirSync(dir); 69 | let dirent; 70 | 71 | while ((dirent = d.readSync()) !== null) { 72 | if (dirent.isDirectory()) 73 | watch_dirs(path.join(dir, dirent.name), on_change); 74 | } 75 | d.closeSync(); 76 | } 77 | 78 | const context = await esbuild.context({ 79 | ...!production ? { sourcemap: "linked" } : {}, 80 | bundle: true, 81 | entryPoints: ['./src/index.js'], 82 | external: ['*.woff', '*.woff2', '*.jpg', '*.svg', '../../assets*'], // Allow external font files which live in ../../static/fonts 83 | legalComments: 'external', // Move all legal comments to a .LEGAL.txt file 84 | loader: { ".js": "jsx" }, 85 | minify: production, 86 | nodePaths, 87 | outdir, 88 | target: ['es2020'], 89 | plugins: [ 90 | cleanPlugin(), 91 | // Esbuild will only copy assets that are explicitly imported and used 92 | // in the code. This is a problem for index.html and manifest.json which are not imported 93 | copy({ 94 | assets: [ 95 | { from: ['./src/manifest.json'], to: ['./manifest.json'] }, 96 | { from: ['./src/index.html'], to: ['./index.html'] }, 97 | ] 98 | }), 99 | ...esbuildStylesPlugins, 100 | cockpitPoEsbuildPlugin(), 101 | ...production ? [cockpitCompressPlugin()] : [], 102 | cockpitRsyncEsbuildPlugin({ dest: packageJson.name }), 103 | notifyEndPlugin(), 104 | ] 105 | }); 106 | 107 | try { 108 | await context.rebuild(); 109 | } catch (e) { 110 | if (!args.watch) 111 | process.exit(1); 112 | // ignore errors in watch mode 113 | } 114 | 115 | if (args.watch) { 116 | const on_change = async path => { 117 | console.log("change detected:", path); 118 | await context.cancel(); 119 | 120 | try { 121 | await context.rebuild(); 122 | } catch (e) {} // ignore in watch mode 123 | }; 124 | 125 | watch_dirs('src', on_change); 126 | 127 | // wait forever until Control-C 128 | await new Promise(() => {}); 129 | } 130 | 131 | context.dispose(); 132 | -------------------------------------------------------------------------------- /org.cockpit-project.sensors.metainfo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.cockpit_project.sensors 4 | CC0-1.0 5 | Sensors 6 | Sensors cockpit module 7 | 8 |

9 | Sensors cockpit module 10 |

11 |
12 | org.cockpit_project.cockpit 13 | sensors 14 | https://github.com/ocristopfer/cockpit-sensors 15 | https://github.com/ocristopfer/cockpit-sensors/issues 16 | cockpit-devel_AT_lists.fedorahosted.org 17 |
18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sensors", 3 | "description": "Module that displays all data reported by lm-sensors", 4 | "type": "module", 5 | "main": "index.js", 6 | "repository": "git@github.com:ocristopfer/cockpit-sensors.git", 7 | "author": "https://github.com/ocristopfer", 8 | "license": "LGPL-2.1", 9 | "engines": { 10 | "node": ">= 16" 11 | }, 12 | "scripts": { 13 | "watch": "ESBUILD_WATCH='true' ./build.js", 14 | "build": "./build.js", 15 | "eslint": "eslint --ext .js --ext .jsx src/", 16 | "eslint:fix": "eslint --fix --ext .js --ext .jsx src/", 17 | "stylelint": "stylelint src/*{.css,scss}", 18 | "stylelint:fix": "stylelint --fix src/*{.css,scss}" 19 | }, 20 | "devDependencies": { 21 | "argparse": "2.0.1", 22 | "chrome-remote-interface": "0.33.0", 23 | "esbuild": "0.20.1", 24 | "esbuild-plugin-copy": "2.1.1", 25 | "esbuild-plugin-replace": "1.4.0", 26 | "esbuild-sass-plugin": "3.1.0", 27 | "esbuild-wasm": "0.20.1", 28 | "eslint": "8.56.0", 29 | "eslint-config-standard": "17.1.0", 30 | "eslint-config-standard-jsx": "11.0.0", 31 | "eslint-config-standard-react": "13.0.0", 32 | "eslint-plugin-import": "2.29.1", 33 | "eslint-plugin-node": "11.1.0", 34 | "eslint-plugin-promise": "6.1.1", 35 | "eslint-plugin-react": "7.33.2", 36 | "eslint-plugin-react-hooks": "4.6.0", 37 | "gettext-parser": "8.0.0", 38 | "htmlparser": "1.7.7", 39 | "jed": "1.1.1", 40 | "qunit": "2.20.1", 41 | "sass": "1.71.1", 42 | "stylelint": "16.2.1", 43 | "stylelint-config-standard": "36.0.0", 44 | "stylelint-config-standard-scss": "13.0.0", 45 | "stylelint-formatter-pretty": "4.0.0" 46 | }, 47 | "dependencies": { 48 | "@patternfly/patternfly": "5.2.0", 49 | "@patternfly/react-core": "5.2.0", 50 | "@patternfly/react-icons": "5.2.0", 51 | "@patternfly/react-styles": "5.2.0", 52 | "react": "18.2.0", 53 | "react-dom": "18.2.0" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packaging/cockpit-sensors.control: -------------------------------------------------------------------------------- 1 | Package: cockpit-sensors 2 | Name: Cockpit Sensors 3 | Description: Cockpit Sensors Module that displays all data reported by lm-sensors. 4 | Author: ocristopfer 5 | Maintainer: ocristopfer 6 | Version: 1.4.2 7 | Depends: lm-sensors 8 | Architecture: all 9 | Homepage: https://github.com/ocristopfer/cockpit-sensors 10 | Website: https://github.com/ocristopfer/cockpit-sensors 11 | -------------------------------------------------------------------------------- /packaging/cockpit-sensors.spec.in: -------------------------------------------------------------------------------- 1 | Name: cockpit-sensors 2 | Version: %{VERSION} 3 | Release: 1%{?dist} 4 | Summary: Cockpit Sensors Module 5 | License: LGPL-2.1-or-later 6 | 7 | Source0: https://github.com/ocristopfer/cockpit-sensors/releases/latest/download/cockpit-sensors.tar.xz 8 | Source1: https://github.com/ocristopfer/cockpit-sensors/releases/latest/download/cockpit-sensors-node.tar.xz 9 | BuildArch: noarch 10 | ExclusiveArch: %{nodejs_arches} noarch 11 | BuildRequires: nodejs 12 | BuildRequires: make 13 | BuildRequires: libappstream-glib 14 | BuildRequires: gettext 15 | %if 0%{?rhel} && 0%{?rhel} <= 8 16 | BuildRequires: libappstream-glib-devel 17 | %endif 18 | 19 | Requires: cockpit-bridge 20 | 21 | %{NPM_PROVIDES} 22 | 23 | %description 24 | Cockpit Sensors Module 25 | 26 | %prep 27 | %autosetup -n %{name} -a 1 28 | # ignore pre-built bundle in release tarball and rebuild it 29 | # but keep it in RHEL/CentOS-8, as that has a too old nodejs 30 | %if ! 0%{?rhel} || 0%{?rhel} >= 9 31 | rm -rf dist 32 | %endif 33 | 34 | %build 35 | NODE_ENV=production make 36 | 37 | %install 38 | %make_install PREFIX=/usr 39 | 40 | # drop source maps, they are large and just for debugging 41 | find %{buildroot}%{_datadir}/cockpit/ -name '*.map' | xargs --no-run-if-empty rm --verbose 42 | 43 | %check 44 | appstream-util validate-relax --nonet %{buildroot}/%{_datadir}/metainfo/* 45 | 46 | # this can't be meaningfully tested during package build; tests happen through 47 | # FMF (see plans/all.fmf) during package gating 48 | 49 | %files 50 | %doc README.md 51 | %license LICENSE dist/index.js.LEGAL.txt dist/index.css.LEGAL.txt 52 | %{_datadir}/cockpit/* 53 | %{_datadir}/metainfo/* 54 | 55 | %changelog 56 | -------------------------------------------------------------------------------- /packit.yaml: -------------------------------------------------------------------------------- 1 | # Enable RPM builds and running integration tests in PRs through https://packit.dev/ 2 | # To use this, enable Packit-as-a-service in GitHub: https://packit.dev/docs/packit-as-a-service/ 3 | # See https://packit.dev/docs/configuration/ for the format of this file 4 | 5 | specfile_path: cockpit-sensors.spec 6 | # use the nicely formatted release description from our upstream release, instead of git shortlog 7 | copy_upstream_release_description: true 8 | 9 | srpm_build_deps: 10 | - make 11 | - nodejs-npm 12 | 13 | actions: 14 | post-upstream-clone: 15 | - make cockpit-sensors.spec 16 | # replace Source1 manually, as create-archive: can't handle multiple tarballs 17 | - make node-cache 18 | - sh -c 'sed -i "/^Source1:/ s/https:.*/$(ls *-node*.tar.xz)/" cockpit-*.spec' 19 | create-archive: make dist 20 | # sensors.git has no release tags; your project can drop this once you have a release 21 | get-current-version: make print-version 22 | 23 | jobs: 24 | - job: copr_build 25 | trigger: pull_request 26 | targets: 27 | - fedora-all 28 | - fedora-latest-aarch64 29 | - centos-stream-8 30 | - centos-stream-9 31 | - centos-stream-9-aarch64 32 | 33 | - job: tests 34 | trigger: pull_request 35 | targets: 36 | - fedora-all 37 | - fedora-latest-aarch64 38 | - centos-stream-8 39 | - centos-stream-9 40 | - centos-stream-9-aarch64 41 | 42 | # Build releases in COPR: https://packit.dev/docs/configuration/#copr_build 43 | - job: copr_build 44 | trigger: release 45 | owner: ocristopfer 46 | project: cockpit-sensors 47 | preserve_project: True 48 | targets: 49 | - fedora-all 50 | - centos-stream-9-x86_64 51 | 52 | # Build releases in Fedora: https://packit.dev/docs/configuration/#propose_downstream 53 | - job: propose_downstream 54 | trigger: release 55 | dist_git_branches: 56 | - fedora-all 57 | 58 | - job: koji_build 59 | trigger: commit 60 | dist_git_branches: 61 | - fedora-all 62 | 63 | - job: bodhi_update 64 | trigger: commit 65 | dist_git_branches: 66 | # rawhide updates are created automatically 67 | - fedora-branched 68 | -------------------------------------------------------------------------------- /plans/all.fmf: -------------------------------------------------------------------------------- 1 | summary: 2 | Run all tests 3 | discover: 4 | how: fmf 5 | execute: 6 | how: tmt 7 | 8 | # Let's handle them upstream only, don't break Fedora/RHEL reverse dependency gating 9 | environment: 10 | TEST_AUDIT_NO_SELINUX: 1 11 | -------------------------------------------------------------------------------- /po/de.po: -------------------------------------------------------------------------------- 1 | # sensors German translations 2 | #, fuzzy 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: sensors 1.0\n" 6 | "Report-Msgid-Bugs-To: \n" 7 | "POT-Creation-Date: 2022-03-09 16:09+0100\n" 8 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 9 | "Last-Translator: FULL NAME \n" 10 | "Language-Team: LANGUAGE \n" 11 | "Language: de\n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Plural-Forms: nplurals=2; plural=n != 1\n" 16 | 17 | #: src/index.html:20 18 | msgid "Cockpit Sensors" 19 | msgstr "Cockpit Sensoren" 20 | 21 | #: src/manifest.json:8 22 | #: org.cockpit-project.sensors.metainfo.xml:5 23 | #: src/app.jsx:162 24 | msgid "Sensors" 25 | msgstr "Sensoren" 26 | 27 | #: org.cockpit-project.sensors.metainfo.xml:8 28 | msgid "Sensors cockpit module" 29 | msgstr "Sensoren Cockpit Modul" 30 | 31 | #: src/app.jsx:86 32 | msgid "lm-sensors not found, you want install it ?" 33 | msgstr "lm-sensors nicht gefunden, möchten Sie es installieren?" 34 | 35 | #: src/app.jsx:95 36 | msgid "this version of lm-sensors don't suport output sensors data!" 37 | msgstr "diese Version von lm-sensors unterstützt keine Ausgabe von Sensordaten!" 38 | 39 | #: src/app.jsx:130 40 | msgid "lm-sensors has a bug that converts all data to fahrenheit, including voltage, fans and etc." 41 | msgstr "lm-sensors hat einen Fehler, der alle Daten in Fahrenheit umwandelt, einschließlich Spannung, Lüfter usw." 42 | 43 | #: src/app.jsx:200 44 | msgid "Show temperature in Fahrenheit" 45 | msgstr "Temperatur in Fahrenheit anzeigen" 46 | 47 | #: src/app.jsx:206 48 | msgid "Expand all cards" 49 | msgstr "Erweitern Sie alle Karten" 50 | 51 | #: src/app.jsx:174 52 | msgid "Install" 53 | msgstr "Installieren" -------------------------------------------------------------------------------- /po/pt_BR.po: -------------------------------------------------------------------------------- 1 | # sensors Portugues translations 2 | #, fuzzy 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: sensors 1.0\n" 6 | "Report-Msgid-Bugs-To: \n" 7 | "POT-Creation-Date: 2022-03-09 16:09+0100\n" 8 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 9 | "Last-Translator: Cristopfer Luis \n" 10 | "Language-Team: LANGUAGE \n" 11 | "Language: pt_BR\n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Plural-Forms: nplurals=2; plural=n != 1\n" 16 | 17 | #: src/index.html:20 18 | msgid "Cockpit Sensors" 19 | msgstr "Sensores para Cockpit" 20 | 21 | #: src/manifest.json:8 22 | #: org.cockpit-project.sensors.metainfo.xml:5 23 | #: src/app.jsx:162 24 | msgid "Sensors" 25 | msgstr "Sensores" 26 | 27 | #: org.cockpit-project.sensors.metainfo.xml:8 28 | msgid "Sensors cockpit module" 29 | msgstr "Sensores do lm-sensors para o cockpit" 30 | 31 | #: src/app.jsx:86 32 | msgid "lm-sensors not found, you want install it ?" 33 | msgstr "Não foi encontrado o lm-sensors, deseja instala-lo?" 34 | 35 | #: src/app.jsx:95 36 | msgid "this version of lm-sensors don't suport output sensors data!" 37 | msgstr "Essa versão do lm-sensors não tem suporte para saida de dados!" 38 | 39 | #: src/app.jsx:130 40 | msgid "lm-sensors has a bug that converts all data to fahrenheit, including voltage, fans and etc." 41 | msgstr "lm-sensors tem um problema aonde ele converte todos os dados para fahrenheit, incluindo voltage, vetoinhas e etc." 42 | 43 | #: src/app.jsx:200 44 | msgid "Show temperature in Fahrenheit" 45 | msgstr "Exibir temperatus em Fahrenheit" 46 | 47 | #: src/app.jsx:206 48 | msgid "Expand all cards" 49 | msgstr "Expandir todos os cards" 50 | 51 | #: src/app.jsx:174 52 | msgid "Install" 53 | msgstr "Instalar" -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.ruff] 2 | exclude = [ 3 | ".git/", 4 | "modules/", 5 | "node_modules/", 6 | ] 7 | line-length = 118 8 | src = [] 9 | 10 | [tool.ruff.lint] 11 | select = [ 12 | "A", # flake8-builtins 13 | "B", # flake8-bugbear 14 | "C4", # flake8-comprehensions 15 | "D300", # pydocstyle: Forbid ''' in docstrings 16 | "E", # pycodestyle 17 | "EXE", # flake8-executable 18 | "F", # pyflakes 19 | "FBT", # flake8-boolean-trap 20 | "G", # flake8-logging-format 21 | "I", # isort 22 | "ICN", # flake8-import-conventions 23 | "ISC", # flake8-implicit-str-concat 24 | "PLE", # pylint errors 25 | "PGH", # pygrep-hooks 26 | "RSE", # flake8-raise 27 | "RUF", # ruff rules 28 | "T10", # flake8-debugger 29 | "TCH", # flake8-type-checking 30 | "UP032", # f-string 31 | "W", # warnings (mostly whitespace) 32 | "YTT", # flake8-2020 33 | ] 34 | ignore = [ 35 | "FBT002", # Boolean default value in function definition 36 | "FBT003", # Boolean positional value in function call 37 | ] 38 | 39 | [tool.ruff.lint.flake8-pytest-style] 40 | fixture-parentheses = false 41 | mark-parentheses = false 42 | 43 | [tool.ruff.lint.isort] 44 | known-first-party = ["cockpit"] 45 | -------------------------------------------------------------------------------- /src/app.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Cockpit. 3 | * 4 | * Copyright (C) 2017 Red Hat, Inc. 5 | * 6 | * Cockpit is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation; either version 2.1 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Cockpit is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Cockpit; If not, see . 18 | */ 19 | 20 | import cockpit from 'cockpit'; 21 | import React from 'react'; 22 | import { Alert, Card, CardTitle, CardHeader, CardBody, CardExpandableContent, Checkbox, Button, Spinner, Flex, FlexItem } from '@patternfly/react-core'; 23 | import { FanIcon, ThermometerHalfIcon, ChargingStationIcon, CpuIcon, EyeSlashIcon } from '@patternfly/react-icons/dist/esm/icons/'; 24 | 25 | const _ = cockpit.gettext; 26 | 27 | export class Application extends React.Component { 28 | constructor() { 29 | super(); 30 | this.state = { sensors: {}, intervalId: {}, alert: null, fahrenheitTemp: [], fahrenheitChecked: false, isShowBtnInstall: false, sensorArgumet: "-j", isShowLoading: false, isExpanded: {}, expandAllCards: false, isError: false, hidedCards: [] }; 31 | } 32 | 33 | componentDidMount() { 34 | const storageHidedCards = localStorage.getItem('hidedCards'); 35 | const hidedCards = storageHidedCards != null && storageHidedCards !== '' ? storageHidedCards.split(',') : []; 36 | const fahrenheitChecked = Boolean(localStorage.getItem('fahrenheitChecked')) || false; 37 | const isExpanded = JSON.parse(localStorage.getItem('isExpanded')) || {}; 38 | const intervalId = setInterval(() => { 39 | if (!this.state.isShowBtnInstall && !this.state.isError) 40 | this.loadSensors(); 41 | }, 1000); 42 | this.setState({ intervalId, hidedCards, fahrenheitChecked, isExpanded }); 43 | } 44 | 45 | componentWillUnmount() { 46 | clearInterval(this.state.intervalId); 47 | } 48 | 49 | loadSensors = () => { 50 | cockpit 51 | .spawn(["sensors", this.state.sensorArgumet], { err: "message", superuser: "try" }) 52 | .done((sucess) => { 53 | if (this.state.sensorArgumet === "-j") { 54 | this.setState({ sensors: JSON.parse(sucess), isShowBtnInstall: false }); 55 | } else { 56 | const sensorsJson = {}; 57 | sucess.split(/\n\s*\n/).forEach(raw => { 58 | let sensorsGroupName = ""; 59 | let index = 0; 60 | let sensorTitle = ""; 61 | raw.split(/\n\s*/).forEach(element => { 62 | if (index === 0) { 63 | sensorsGroupName = element; 64 | sensorsJson[sensorsGroupName] = {}; 65 | } 66 | if (index === 1) { 67 | const adapter = element.split(":"); 68 | sensorsJson[sensorsGroupName][adapter[0]] = adapter[1].trim(); 69 | } 70 | if (index >= 2) { 71 | const sensor = element.trim().split(":"); 72 | if (sensor[1] === "") { 73 | sensorTitle = element.split(":")[0]; 74 | sensorsJson[sensorsGroupName][sensorTitle] = {}; 75 | } else { 76 | sensorsJson[sensorsGroupName][sensorTitle][sensor[0]] = parseFloat(sensor[1].trim()); 77 | } 78 | } 79 | 80 | index += 1; 81 | }); 82 | }); 83 | this.setState({ sensors: sensorsJson, isShowBtnInstall: false }); 84 | } 85 | }) 86 | .fail((err) => { 87 | if (err.message === "not-found") { 88 | this.setState({ isShowBtnInstall: true }); 89 | this.setAlert(_('lm-sensors not found, you want install it ?'), 'danger'); 90 | this.getLmSensorsInstallCmd(0); 91 | return; 92 | } 93 | if (err.message === "sensors: invalid option -- 'j'") { 94 | this.setState({ sensorArgumet: "-u" }); 95 | return; 96 | } 97 | 98 | if (err.message === "sensors: invalid option -- 'u'") { 99 | this.setAlert(_("this version of lm-sensors don't suport output sensors data!"), 'danger'); 100 | this.setState({ isError: true }); 101 | return; 102 | } 103 | this.setAlert(err.message, 'warning'); 104 | clearInterval(this.state.intervalId); 105 | }); 106 | }; 107 | 108 | setIcon = (name) => { 109 | if (typeof name !== 'undefined') { 110 | if (name.includes('fan')) { 111 | return ; 112 | } 113 | if (name.includes('temp')) { 114 | return ; 115 | } 116 | if (name.includes('in')) { 117 | return ; 118 | } 119 | if (name.includes('cpu')) { 120 | return ; 121 | } 122 | } 123 | return <>; 124 | }; 125 | 126 | adjustLabel = (label) => { 127 | return label.replace(label.substring(0, label.indexOf('_')) + '_', ''); 128 | }; 129 | 130 | setAlert = (msg, variant) => { 131 | this.setState({ alert: { msg, variant } }); 132 | }; 133 | 134 | handleChangeFahrenheit = (event, checked) => { 135 | this.setState({ fahrenheitChecked: checked }); 136 | localStorage.setItem('fahrenheitChecked', checked); 137 | if (checked) { 138 | this.setState({ fahrenheitTemp: ['-f'] }); 139 | } else { 140 | this.setState({ fahrenheitTemp: [] }); 141 | } 142 | }; 143 | 144 | handleChangeCards = (event, checked) => { 145 | const isExpanded = this.state.isExpanded; 146 | Object.keys(isExpanded).forEach((element) => { 147 | isExpanded[element] = checked; 148 | }); 149 | localStorage.setItem('isExpanded', JSON.stringify(isExpanded)); 150 | this.setState({ isExpanded, expandAllCards: checked }); 151 | }; 152 | 153 | lstPacktsManager = ["apk", "apt-get", "dnf", "zypper"]; 154 | installCmd = null; 155 | getLmSensorsInstallCmd = async (index) => { 156 | const cmd = this.lstPacktsManager[index]; 157 | await cockpit.spawn([cmd, "-v"]) 158 | .then((sucesso) => { 159 | switch (cmd) { 160 | case "apk": 161 | this.installCmd = [cmd, "add", "--no-cache", "lm-sensors", "-y"]; 162 | break; 163 | case "dnf": 164 | this.installCmd = [cmd, "install", "lm_sensors", "-y"]; 165 | break; 166 | case "zypper": 167 | this.installCmd = [cmd, "install", "-y", "sensors"]; 168 | break; 169 | case "apt-get": 170 | default: 171 | this.installCmd = [cmd, "install", "lm-sensors", "-y"]; 172 | } 173 | }) 174 | .fail((e) => { 175 | this.getLmSensorsInstallCmd(index + 1); 176 | }); 177 | }; 178 | 179 | handleInstallSensors = async () => { 180 | this.setState({ isShowLoading: true }); 181 | cockpit.spawn(this.installCmd, { err: "message", superuser: "require" }) 182 | .done((sucess) => { 183 | this.setState({ isShowLoading: false, isShowBtnInstall: false, alert: null }); 184 | cockpit.spawn(["sensors-detect", "--auto"], { err: "message", superuser: "require" }) 185 | .done((sucess) => { 186 | cockpit.spawn(["modprobe", "coretemp"], { err: "message", superuser: "require" }); 187 | cockpit.spawn(["modprobe", "i2c-i801"], { err: "message", superuser: "require" }); 188 | cockpit.spawn(["modprobe", "drivetemp"], { err: "message", superuser: "require" }); 189 | }) 190 | .fail((err) => { 191 | this.setAlert(err.message, 'warning'); 192 | }); 193 | }) 194 | .fail((err) => { 195 | this.setState({ isShowLoading: false, isShowBtnInstall: true }); 196 | this.setAlert(err.message, 'warning'); 197 | }); 198 | }; 199 | 200 | adjustValue = (name, value) => { 201 | if (typeof name !== 'undefined') { 202 | if (name.includes('temp')) { 203 | return this.state.fahrenheitChecked 204 | ? parseFloat((value * 9 / 5) + 32).toFixed(1) 205 | .toString() 206 | .concat(' °F') 207 | : parseFloat(value).toFixed(1) 208 | .toString() 209 | .concat(' °C'); 210 | } 211 | 212 | if (name.includes('fan')) { 213 | return value.toString().concat(' RPM'); 214 | } 215 | } 216 | return value; 217 | }; 218 | 219 | handleOnExpand = (event, id) => { 220 | const isExpanded = this.state.isExpanded; 221 | isExpanded[id] = !isExpanded[id]; 222 | this.setState({ isExpanded }); 223 | }; 224 | 225 | hideCard(cardId) { 226 | const hidedCards = this.state.hidedCards; 227 | hidedCards.push(cardId); 228 | localStorage.setItem('hidedCards', hidedCards); 229 | this.setState({ hidedCards }); 230 | } 231 | 232 | handleShowHidedCards() { 233 | const hidedCards = []; 234 | localStorage.setItem('hidedCards', hidedCards); 235 | this.setState({ hidedCards }); 236 | } 237 | 238 | render() { 239 | const { sensors, alert, fahrenheitChecked, isShowBtnInstall, isShowLoading, isExpanded, expandAllCards, hidedCards } = this.state; 240 | return ( 241 | <> 242 | 243 | {_('Sensors')} 244 | 245 | 252 | 259 | {isShowLoading ? : <>} 260 | {alert != null ? {alert.msg} : <>} 261 | {isShowBtnInstall ? : <>} 262 | {hidedCards.length > 0 ? : <>} 263 | 264 | {sensors !== null 265 | ? Object.entries(sensors).map((key, keyIndex) => { 266 | if (hidedCards.includes(key[0])) { 267 | return (''); 268 | } 269 | return ( 270 | 271 | {key[0]} 272 | 275 | 276 | 277 | 278 | {key[1].Adapter} 279 | 280 | 281 | {Object.entries(key[1]).map((item, itemIndex) => { 282 | if (itemIndex === 0) return ""; 283 | const chave = keyIndex.toString() + itemIndex.toString(); 284 | if (isExpanded[chave] === undefined) { 285 | isExpanded[chave] = false; 286 | } 287 | if (hidedCards.includes(chave)) { 288 | return (''); 289 | } 290 | return ( 291 | 292 | 293 | 294 | this.handleOnExpand(e, chave)} 297 | toggleButtonProps={{ 298 | id: 'toggle-button2', 299 | 'aria-label': 'Patternfly Details', 300 | 'aria-expanded': isExpanded[chave] 301 | }} 302 | >{item[0]} 303 | 306 | 307 | {this.setIcon(Object.keys(item[1])[0])} {this.adjustValue(Object.keys(item[1])[0], Object.values(item[1])[0])} 308 | 309 | 310 | 311 | {Object.entries(item[1]).map((sensors, index) => ( 312 | {this.adjustLabel(sensors[0])}: {sensors[1]}
313 | ))} 314 |
315 |
316 |
317 |
318 | ); 319 | })} 320 |
321 |
322 |
323 | ); 324 | } 325 | ) 326 | : ''} 327 |
328 |
329 | 330 | ); 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /src/app.scss: -------------------------------------------------------------------------------- 1 | @use "page.scss"; 2 | 3 | p { 4 | font-weight: bold; 5 | } 6 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | Cockpit Starter Kit 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Cockpit. 3 | * 4 | * Copyright (C) 2017 Red Hat, Inc. 5 | * 6 | * Cockpit is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation; either version 2.1 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Cockpit is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Cockpit; If not, see . 18 | */ 19 | 20 | import "cockpit-dark-theme"; 21 | import "patternfly/patternfly-5-cockpit.scss"; 22 | 23 | import React from 'react'; 24 | import { createRoot } from 'react-dom/client'; 25 | import { Application } from './app.jsx'; 26 | import './app.scss'; 27 | 28 | document.addEventListener("DOMContentLoaded", () => { 29 | createRoot(document.getElementById("app")).render(); 30 | }); 31 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": { 3 | "cockpit": "137" 4 | }, 5 | "tools": { 6 | "index": { 7 | "label": "Sensors" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /test/browser/browser.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eux 3 | 4 | export TEST_BROWSER=${TEST_BROWSER:-firefox} 5 | 6 | TESTS="$(realpath $(dirname "$0"))" 7 | export SOURCE="$(realpath $TESTS/../..)" 8 | export LOGS="${TMT_TEST_DATA:-$(pwd)/logs}" 9 | mkdir -p "$LOGS" 10 | chmod a+w "$LOGS" 11 | 12 | # HACK: https://bugzilla.redhat.com/show_bug.cgi?id=2033020 13 | dnf update -y pam || true 14 | 15 | # install firefox (available everywhere in Fedora and RHEL) 16 | # we don't need the H.264 codec, and it is sometimes not available (rhbz#2005760) 17 | dnf install --disablerepo=fedora-cisco-openh264 -y --setopt=install_weak_deps=False firefox 18 | 19 | # nodejs 10 is too old for current Cockpit test API 20 | if grep -q platform:el8 /etc/os-release; then 21 | dnf module switch-to -y nodejs:16 22 | fi 23 | 24 | # create user account for logging in 25 | if ! id admin 2>/dev/null; then 26 | useradd -c Administrator -G wheel admin 27 | echo admin:foobar | chpasswd 28 | fi 29 | 30 | # set root's password 31 | echo root:foobar | chpasswd 32 | 33 | # avoid sudo lecture during tests 34 | su -c 'echo foobar | sudo --stdin whoami' - admin 35 | 36 | # create user account for running the test 37 | if ! id runtest 2>/dev/null; then 38 | useradd -c 'Test runner' runtest 39 | # allow test to set up things on the machine 40 | mkdir -p /root/.ssh 41 | curl https://raw.githubusercontent.com/cockpit-project/bots/main/machine/identity.pub >> /root/.ssh/authorized_keys 42 | chmod 600 /root/.ssh/authorized_keys 43 | fi 44 | chown -R runtest "$SOURCE" 45 | 46 | # disable core dumps, we rather investigate them upstream where test VMs are accessible 47 | echo core > /proc/sys/kernel/core_pattern 48 | 49 | systemctl enable --now cockpit.socket 50 | 51 | # Run tests as unprivileged user 52 | # once we drop support for RHEL 8, use this: 53 | # runuser -u runtest --whitelist-environment=TEST_BROWSER,TEST_ALLOW_JOURNAL_MESSAGES,TEST_AUDIT_NO_SELINUX,SOURCE,LOGS $TESTS/run-test.sh 54 | runuser -u runtest --preserve-environment env USER=runtest HOME=$(getent passwd runtest | cut -f6 -d:) $TESTS/run-test.sh 55 | 56 | RC=$(cat $LOGS/exitcode) 57 | exit ${RC:-1} 58 | -------------------------------------------------------------------------------- /test/browser/main.fmf: -------------------------------------------------------------------------------- 1 | summary: 2 | Run browser integration tests on the host 3 | require: 4 | - cockpit-sensors 5 | - cockpit-ws 6 | - cockpit-system 7 | - bzip2 8 | - git-core 9 | - glibc-langpack-de 10 | - libvirt-python3 11 | - make 12 | - npm 13 | - python3 14 | test: ./browser.sh 15 | duration: 60m 16 | -------------------------------------------------------------------------------- /test/browser/run-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eux 3 | 4 | # tests need cockpit's bots/ libraries and test infrastructure 5 | cd $SOURCE 6 | git init 7 | rm -f bots # common local case: existing bots symlink 8 | make bots test/common 9 | 10 | # support running from clean git tree 11 | if [ ! -d node_modules/chrome-remote-interface ]; then 12 | # copy package.json temporarily otherwise npm might try to install the dependencies from it 13 | rm -f package-lock.json # otherwise the command below installs *everything*, argh 14 | mv package.json .package.json 15 | # only install a subset to save time/space 16 | npm install chrome-remote-interface 17 | mv .package.json package.json 18 | fi 19 | 20 | # disable detection of affected tests; testing takes too long as there is no parallelization 21 | mv .git dot-git 22 | 23 | . /etc/os-release 24 | export TEST_OS="${ID}-${VERSION_ID/./-}" 25 | 26 | if [ "${TEST_OS#centos-}" != "$TEST_OS" ]; then 27 | TEST_OS="${TEST_OS}-stream" 28 | fi 29 | 30 | EXCLUDES="" 31 | 32 | # make it easy to check in logs 33 | echo "TEST_ALLOW_JOURNAL_MESSAGES: ${TEST_ALLOW_JOURNAL_MESSAGES:-}" 34 | echo "TEST_AUDIT_NO_SELINUX: ${TEST_AUDIT_NO_SELINUX:-}" 35 | 36 | RC=0 37 | test/common/run-tests --nondestructive --machine 127.0.0.1:22 --browser 127.0.0.1:9090 $EXCLUDES || RC=$? 38 | 39 | echo $RC > "$LOGS/exitcode" 40 | cp --verbose Test* "$LOGS" || true 41 | # deliver test result via exitcode file 42 | exit 0 43 | -------------------------------------------------------------------------------- /test/check-application: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 -cimport os, sys; os.execv(os.path.dirname(sys.argv[1]) + "/common/pywrap", sys.argv) 2 | 3 | # Run this with --help to see available options for tracing and debugging 4 | # See https://github.com/cockpit-project/cockpit/blob/main/test/common/testlib.py 5 | # "class Browser" and "class MachineCase" for the available API. 6 | 7 | import testlib 8 | 9 | 10 | # Nondestructive tests all run in the same running VM. This allows them to run in Packit, Fedora, and 11 | # RHEL dist-git gating. They must not permanently change any file or configuration on the system in a 12 | # way that influences other tests. 13 | # temporary inactive teste 14 | @testlib.nondestructive 15 | class TestApplication(testlib.MachineCase): 16 | def testBasic(self): 17 | b = self.browser 18 | m = self.machine 19 | 20 | self.login_and_go("/sensors") 21 | # verify expected heading 22 | b.wait_text(".pf-v5-c-card__title-text", "Sensors") 23 | 24 | 25 | if __name__ == '__main__': 26 | testlib.test_main() 27 | -------------------------------------------------------------------------------- /test/reference-image: -------------------------------------------------------------------------------- 1 | fedora-35 2 | -------------------------------------------------------------------------------- /test/run: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | set -eu 3 | 4 | # This is the expected entry point for Cockpit CI; will be called without 5 | # arguments but with an appropriate $TEST_OS, and optionally $TEST_SCENARIO 6 | 7 | TEST_SCENARIO="${TEST_SCENARIO:-}" 8 | [ "${TEST_SCENARIO}" = "${TEST_SCENARIO##firefox}" ] || export TEST_BROWSER=firefox 9 | export RUN_TESTS_OPTIONS=--track-naughties 10 | 11 | make codecheck 12 | make check 13 | -------------------------------------------------------------------------------- /test/vm.install: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # image-customize script to prepare a bots VM for testing this application 3 | # The application package will be installed separately 4 | set -eu 5 | 6 | # don't force https:// (self-signed cert) 7 | printf "[WebService]\\nAllowUnencrypted=true\\n" > /etc/cockpit/cockpit.conf 8 | 9 | if type firewall-cmd >/dev/null 2>&1; then 10 | firewall-cmd --add-service=cockpit --permanent 11 | fi 12 | systemctl enable cockpit.socket 13 | --------------------------------------------------------------------------------