From 1c6f8848b3af1f4d42ae4a365c407ae8a2de2163 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Fri, 8 Nov 2024 09:05:22 +0100 Subject: [PATCH] Move to PatternFly Elements and lit PFE uses lit, so it makes sense to just use that for the main application as well. Web components are pretty much React built into the web platform, and lit adds some convenience around that. This is mostly a demo -- for real Cockpit pages, PF Elements is still missing too many components. --- .eslintrc.json | 11 +----- .github/dependabot.yml | 4 --- package.json | 14 ++------ packaging/cockpit-starter-kit.spec.in | 2 +- src/app.scss | 5 --- src/{app.tsx => ct-application.ts} | 50 +++++++++++++++------------ src/index.html | 2 +- src/{index.tsx => index.ts} | 16 ++------- test/browser/run-test.sh | 13 +++++++ test/check-application | 8 ++--- tsconfig.json | 1 - 11 files changed, 52 insertions(+), 74 deletions(-) delete mode 100644 src/app.scss rename src/{app.tsx => ct-application.ts} (50%) rename src/{index.tsx => index.ts} (64%) diff --git a/.eslintrc.json b/.eslintrc.json index d499b3eb..08c37301 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,12 +4,11 @@ "browser": true, "es6": true }, - "extends": ["eslint:recommended", "standard", "standard-jsx", "standard-react"], + "extends": ["eslint:recommended", "standard"], "parserOptions": { "ecmaVersion": "2022", "sourceType": "module" }, - "plugins": ["react", "react-hooks"], "rules": { "indent": ["error", 4, { @@ -22,12 +21,8 @@ "no-var": "error", "lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }], "prefer-promise-reject-errors": ["error", { "allowEmptyReject": true }], - "react/jsx-indent": ["error", 4], "semi": ["error", "always", { "omitLastInOneLineBlock": true }], - "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "error", - "camelcase": "off", "comma-dangle": "off", "curly": "off", @@ -35,10 +30,6 @@ "key-spacing": "off", "no-console": "off", "quotes": "off", - "react/jsx-curly-spacing": "off", - "react/jsx-indent-props": "off", - "react/jsx-no-useless-fragment": "error", - "react/prop-types": "off", "space-before-function-paren": "off", "standard/no-callback-literal": "off" }, diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0526b5fc..dd9e50bb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -30,10 +30,6 @@ updates: - "types*" ignore: - # https://github.com/cockpit-project/cockpit/issues/21151 - - dependency-name: "sass" - versions: [">=1.80.0", "2.x"] - # needs to be done in Cockpit first - dependency-name: "@patternfly/*" update-types: ["version-update:semver-major"] diff --git a/package.json b/package.json index 3b97fab7..d412d6e0 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,6 @@ "stylelint:fix": "stylelint --fix src/*{.css,scss}" }, "devDependencies": { - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", "@typescript-eslint/eslint-plugin": "8.15.0", "argparse": "2.0.1", "esbuild": "0.24.0", @@ -30,18 +28,14 @@ "eslint": "8.57.1", "eslint-config-standard": "17.1.0", "eslint-config-standard-jsx": "11.0.0", - "eslint-config-standard-react": "13.0.0", "eslint-plugin-import": "2.31.0", "eslint-plugin-node": "11.1.0", "eslint-plugin-promise": "6.6.0", - "eslint-plugin-react": "7.37.2", - "eslint-plugin-react-hooks": "4.6.2", "gettext-parser": "8.0.0", "glob": "11.0.0", "htmlparser": "1.7.7", "jed": "1.1.1", "qunit": "2.22.0", - "sass": "1.79.6", "stylelint": "16.10.0", "stylelint-config-recommended-scss": "14.0.0", "stylelint-config-standard": "36.0.1", @@ -50,11 +44,7 @@ "typescript": "5.6.3" }, "dependencies": { - "@patternfly/patternfly": "5.4.2", - "@patternfly/react-core": "5.4.8", - "@patternfly/react-icons": "5.4.2", - "@patternfly/react-styles": "5.4.1", - "react": "18.3.1", - "react-dom": "18.3.1" + "@patternfly/elements": "4.0.2", + "lit": "3.2.1" } } diff --git a/packaging/cockpit-starter-kit.spec.in b/packaging/cockpit-starter-kit.spec.in index 14cd470c..e9a650f0 100644 --- a/packaging/cockpit-starter-kit.spec.in +++ b/packaging/cockpit-starter-kit.spec.in @@ -57,7 +57,7 @@ appstream-util validate-relax --nonet %{buildroot}/%{_datadir}/metainfo/* %files %doc README.md -%license LICENSE dist/index.js.LEGAL.txt dist/index.css.LEGAL.txt +%license LICENSE dist/index.js.LEGAL.txt %{_datadir}/cockpit/* %{_datadir}/metainfo/* diff --git a/src/app.scss b/src/app.scss deleted file mode 100644 index 6d2c5d8b..00000000 --- a/src/app.scss +++ /dev/null @@ -1,5 +0,0 @@ -@use "page.scss"; - -p { - font-weight: bold; -} diff --git a/src/app.tsx b/src/ct-application.ts similarity index 50% rename from src/app.tsx rename to src/ct-application.ts index 0d3b12fd..a06e7d62 100644 --- a/src/app.tsx +++ b/src/ct-application.ts @@ -1,7 +1,7 @@ /* * This file is part of Cockpit. * - * Copyright (C) 2017 Red Hat, Inc. + * Copyright (C) 2024 Red Hat, Inc. * * Cockpit is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by @@ -17,32 +17,36 @@ * along with Cockpit; If not, see . */ -import React, { useEffect, useState } from 'react'; -import { Alert } from "@patternfly/react-core/dist/esm/components/Alert/index.js"; -import { Card, CardBody, CardTitle } from "@patternfly/react-core/dist/esm/components/Card/index.js"; +import { css, html, LitElement } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; + +import '@patternfly/elements/pf-card/pf-card.js'; import cockpit from 'cockpit'; const _ = cockpit.gettext; -export const Application = () => { - const [hostname, setHostname] = useState(_("Unknown")); +@customElement('ct-application') +export class Application extends LitElement { + @state() private accessor hostname = _("Unknown"); + + static readonly styles = css` + .running-on { + color: green; + } + `; - useEffect(() => { + connectedCallback() { + super.connectedCallback(); const hostname = cockpit.file('/etc/hostname'); - hostname.watch(content => setHostname(content?.trim() ?? "")); - return hostname.close; - }, []); - - return ( - - Starter Kit - - - - - ); -}; + hostname.watch(content => { this.hostname = content?.trim() ?? "" }); + } + + render() { + return html` + +

Starter Kit

+

${cockpit.format(_("Running on $0"), this.hostname)}

+
`; + } +} diff --git a/src/index.html b/src/index.html index 2b06bb4f..f034309f 100644 --- a/src/index.html +++ b/src/index.html @@ -29,6 +29,6 @@ -
+ diff --git a/src/index.tsx b/src/index.ts similarity index 64% rename from src/index.tsx rename to src/index.ts index 51254c0a..a85da714 100644 --- a/src/index.tsx +++ b/src/index.ts @@ -1,7 +1,7 @@ /* * This file is part of Cockpit. * - * Copyright (C) 2017 Red Hat, Inc. + * Copyright (C) 2024 Red Hat, Inc. * * Cockpit is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by @@ -17,16 +17,6 @@ * along with Cockpit; If not, see . */ -import React from 'react'; -import { createRoot } from 'react-dom/client'; +// import "cockpit-dark-theme"; // doesn't work for PFE -import "cockpit-dark-theme"; - -import { Application } from './app.jsx'; - -import "patternfly/patternfly-5-cockpit.scss"; -import './app.scss'; - -document.addEventListener("DOMContentLoaded", () => { - createRoot(document.getElementById("app")!).render(); -}); +import './ct-application.ts'; diff --git a/test/browser/run-test.sh b/test/browser/run-test.sh index 586583d9..9a33db99 100644 --- a/test/browser/run-test.sh +++ b/test/browser/run-test.sh @@ -7,6 +7,19 @@ git init rm -f bots # common local case: existing bots symlink make bots test/common +# support running from clean git tree +if [ -e .git ]; then + # move package.json temporarily otherwise npm might try to install the dependencies from it + rm -f package-lock.json # otherwise the command below installs *everything*, argh + mv package.json .package.json + # only install a subset to save time/space + npm install query-selector-shadow-dom + mv .package.json package.json +else + # upstream tarballs ship test dependencies; print version for debugging + grep '"version"' node_modules/query-selector-shadow-dom/package.json +fi + # disable detection of affected tests; testing takes too long as there is no parallelization mv .git dot-git diff --git a/test/check-application b/test/check-application index 3e85d0f9..cc362e12 100755 --- a/test/check-application +++ b/test/check-application @@ -18,16 +18,16 @@ class TestApplication(testlib.MachineCase): self.login_and_go("/starter-kit") # verify expected heading - b.wait_text(".pf-v5-c-card__title", "Starter Kit") + b.wait_text("pf-card [slot='header']", "Starter Kit") # verify expected host name hostname = m.execute("cat /etc/hostname").strip() - b.wait_in_text(".pf-v5-c-alert__title", "Running on " + hostname) + b.wait_in_text("pf-card .running-on", "Running on " + hostname) # change current hostname self.write_file("/etc/hostname", "new-" + hostname) # verify new hostname name - b.wait_in_text(".pf-v5-c-alert__title", "Running on new-" + hostname) + b.wait_in_text("pf-card .running-on", "Running on new-" + hostname) # change language to German b.switch_to_top() @@ -46,7 +46,7 @@ class TestApplication(testlib.MachineCase): b.go("/starter-kit") b.enter_page("/starter-kit") # page label (from js) should be translated - b.wait_in_text(".pf-v5-c-alert__title", "Läuft auf") + b.wait_in_text("pf-card .running-on", "Läuft auf") if __name__ == '__main__': diff --git a/tsconfig.json b/tsconfig.json index c4b1669d..e0e3c019 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,6 @@ "allowJs": true, "checkJs": true, "exactOptionalPropertyTypes": true, - "jsx": "react", "lib": [ "dom", "es2020"