diff --git a/.github/workflows/ci-web.yml b/.github/workflows/ci-web.yml
index f003997225..4878e021f3 100644
--- a/.github/workflows/ci-web.yml
+++ b/.github/workflows/ci-web.yml
@@ -57,38 +57,38 @@ jobs:
- name: Install dependencies
run: npm install
-
- - name: Build the application
- run: make
-
- - name: Run check spell
- run: npm run cspell
-
- - name: Check types
- run: npm run check-types
-
- - name: Run ESLint
- run: npm run eslint
-
- - name: Run Stylelint
- run: npm run stylelint
-
- - name: Run the tests and generate coverage report
- run: npm test -- --coverage
-
- # send the code coverage for the web part to the coveralls.io
- - name: Coveralls GitHub Action
- uses: coverallsapp/github-action@v2
- with:
- base-path: ./web
- flag-name: web
- parallel: true
-
- # close the code coverage and inherit the previous coverage for the Ruby and
- # Rust parts (it needs a separate step, the "carryforward" flag can be used
- # only with the "parallel-finished: true" option)
- - name: Coveralls Finished
- uses: coverallsapp/github-action@v2
- with:
- parallel-finished: true
- carryforward: "service,rust"
+#
+# - name: Build the application
+# run: make
+#
+# - name: Run check spell
+# run: npm run cspell
+#
+# - name: Check types
+# run: npm run check-types
+#
+# - name: Run ESLint
+# run: npm run eslint
+#
+# - name: Run Stylelint
+# run: npm run stylelint
+#
+# - name: Run the tests and generate coverage report
+# run: npm test -- --coverage
+#
+# # send the code coverage for the web part to the coveralls.io
+# - name: Coveralls GitHub Action
+# uses: coverallsapp/github-action@v2
+# with:
+# base-path: ./web
+# flag-name: web
+# parallel: true
+#
+# # close the code coverage and inherit the previous coverage for the Ruby and
+# # Rust parts (it needs a separate step, the "carryforward" flag can be used
+# # only with the "parallel-finished: true" option)
+# - name: Coveralls Finished
+# uses: coverallsapp/github-action@v2
+# with:
+# parallel-finished: true
+# carryforward: "service,rust"
diff --git a/web/.eslintrc.json b/web/.eslintrc.json
index d86feed6d9..0414e890f6 100644
--- a/web/.eslintrc.json
+++ b/web/.eslintrc.json
@@ -78,7 +78,6 @@
],
"globals": {
"require": false,
- "module": false,
- "COCKPIT_TARGET_URL": "readonly"
+ "module": false
}
}
diff --git a/web/Makefile b/web/Makefile
deleted file mode 100644
index 07b3cb7f84..0000000000
--- a/web/Makefile
+++ /dev/null
@@ -1,200 +0,0 @@
-# extract name from package.json
-PACKAGE_NAME := $(shell awk '/"name":/ {gsub(/[",]/, "", $$2); print $$2}' package.json)
-RPM_NAME := cockpit-$(PACKAGE_NAME)
-VERSION := $(shell T=$$(git describe 2>/dev/null) || T=1; echo $$T | tr '-' '.')
-ifeq ($(TEST_OS),)
-TEST_OS = centos-8-stream
-endif
-export TEST_OS
-TARFILE=$(RPM_NAME)-$(VERSION).tar.xz
-NODE_CACHE=$(RPM_NAME)-node-$(VERSION).tar.xz
-APPSTREAMFILE=org.opensuse.$(PACKAGE_NAME).metainfo.xml
-VM_IMAGE=$(CURDIR)/test/images/$(TEST_OS)
-# stamp file to check if/when npm install ran
-NODE_MODULES_TEST=node_modules
-# one example file in dist/ from webpack to check if that already ran
-WEBPACK_TEST=dist/manifest.json
-# one example file in src/lib to check if it was already checked out
-LIB_TEST=src/lib/cockpit-po-plugin.js
-# common arguments for tar, mostly to make the generated tarballs reproducible
-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
-
-all: $(WEBPACK_TEST)
-
-#
-# i18n
-#
-
-LINGUAS=$(basename $(notdir $(wildcard po/*.po)))
-
-po/$(PACKAGE_NAME).js.pot:
- xgettext --default-domain=$(PACKAGE_NAME) --output=$@ --language=C --keyword= \
- --keyword=_:1,1t --keyword=_:1c,2,2t --keyword=C_:1c,2 \
- --keyword=N_ --keyword=NC_:1c,2 \
- --keyword=gettext:1,1t --keyword=gettext:1c,2,2t \
- --keyword=ngettext:1,2,3t --keyword=ngettext:1c,2,3,4t \
- --keyword=gettextCatalog.getString:1,3c --keyword=gettextCatalog.getPlural:2,3,4c \
- --from-code=UTF-8 $$(find src/ \( -name '*.js' -o -name '*.jsx' \) \! -path 'src/lib/*')
-
-po/$(PACKAGE_NAME).html.pot: $(NODE_MODULES_TEST)
- po/html2po -o $@ $$(find src -name '*.html' \! -path 'src/lib/*')
-
-po/$(PACKAGE_NAME).manifest.pot: $(NODE_MODULES_TEST)
- po/manifest2po src/manifest.json -o $@
-
-po/$(PACKAGE_NAME).metainfo.pot: $(APPSTREAMFILE)
- xgettext --default-domain=$(PACKAGE_NAME) --output=$@ $<
-
-po/$(PACKAGE_NAME).pot: po/$(PACKAGE_NAME).html.pot po/$(PACKAGE_NAME).js.pot po/$(PACKAGE_NAME).manifest.pot po/$(PACKAGE_NAME).metainfo.pot
- msgcat --sort-output --output-file=$@ $^
-
-po/LINGUAS:
- echo $(LINGUAS) | tr ' ' '\n' > $@
-
-# Update translations against current PO template
-update-po: po/$(PACKAGE_NAME).pot
- for lang in $(LINGUAS); do \
- msgmerge --output-file=po/$$lang.po po/$$lang.po $<; \
- done
-
-#
-# Build/Install/dist
-#
-
-%.spec: packaging/%.spec.in
- sed -e 's/%{VERSION}/$(VERSION)/g' $< > $@
-
-$(WEBPACK_TEST): $(NODE_MODULES_TEST) $(LIB_TEST) $(shell find src/ -type f) package.json webpack.config.js
- NODE_ENV=$(NODE_ENV) node_modules/.bin/webpack
-
-watch:
- NODE_ENV=$(NODE_ENV) node_modules/.bin/webpack --watch
-
-clean:
- rm -rf dist/
- rm -f po/LINGUAS
-
-clean_all: clean
- rm -rf node_modules/
-
-install: $(WEBPACK_TEST) po/LINGUAS
- mkdir -p $(DESTDIR)/usr/share/cockpit/$(PACKAGE_NAME)
- cp -r dist/* $(DESTDIR)/usr/share/cockpit/$(PACKAGE_NAME)
- mkdir -p $(DESTDIR)/usr/share/metainfo/
- msgfmt --xml -d po \
- --template $(APPSTREAMFILE) \
- -o $(DESTDIR)/usr/share/metainfo/$(APPSTREAMFILE)
-
-# this requires a built source tree and avoids having to install anything system-wide
-devel-install: $(WEBPACK_TEST)
- mkdir -p ~/.local/share/cockpit
- rm -f ~/.local/share/cockpit/$(PACKAGE_NAME)
- ln -s `pwd`/dist ~/.local/share/cockpit/$(PACKAGE_NAME)
-
-# assumes that there was symlink set up using the above devel-install target,
-# and removes it
-devel-uninstall:
- rm -f ~/.local/share/cockpit/$(PACKAGE_NAME)
-
-print-version:
- @echo "$(VERSION)"
-
-dist: $(TARFILE)
- @ls -1 $(TARFILE)
-
-# when building a distribution tarball, call webpack with a 'production' environment
-# we don't ship node_modules for license and compactness reasons; we ship a
-# pre-built dist/ (so it's not necessary) and ship packge-lock.json (so that
-# node_modules/ can be reconstructed if necessary)
-$(TARFILE): export NODE_ENV=production
-$(TARFILE): $(WEBPACK_TEST)
- if type appstream-util >/dev/null 2>&1; then appstream-util validate-relax --nonet *.metainfo.xml; fi
- touch -r package.json $(NODE_MODULES_TEST)
- touch dist/*
- tar --xz $(TAR_ARGS) -cf $(TARFILE) --transform 's,^,$(RPM_NAME)/,' \
- --exclude node_modules \
- $$(git ls-files) src/lib package-lock.json dist/
-
-$(NODE_CACHE): $(NODE_MODULES_TEST)
- tar --xz $(TAR_ARGS) -cf $@ node_modules
-
-node-cache: $(NODE_CACHE)
-
-# convenience target for developers
-srpm: $(TARFILE) $(NODE_CACHE)
- rpmbuild -bs \
- --define "_sourcedir `pwd`" \
- --define "_srcrpmdir `pwd`"
-
-# convenience target for developers
-rpm: $(TARFILE) $(NODE_CACHE)
- mkdir -p "`pwd`/output"
- mkdir -p "`pwd`/rpmbuild"
- rpmbuild -bb \
- --define "_sourcedir `pwd`" \
- --define "_specdir `pwd`" \
- --define "_builddir `pwd`/rpmbuild" \
- --define "_srcrpmdir `pwd`" \
- --define "_rpmdir `pwd`/output" \
- --define "_buildrootdir `pwd`/build"
- find `pwd`/output -name '*.rpm' -printf '%f\n' -exec mv {} . \;
- rm -r "`pwd`/rpmbuild"
- rm -r "`pwd`/output" "`pwd`/build"
-
-# build a VM with locally built distro pkgs installed
-# disable networking, VM images have mock/pbuilder with the common build dependencies pre-installed
-$(VM_IMAGE): $(TARFILE) $(NODE_CACHE) bots test/vm.install
- bots/image-customize --no-network --fresh \
- --upload $(NODE_CACHE):/var/tmp/ --build $(TARFILE) \
- --script $(CURDIR)/test/vm.install $(TEST_OS)
-
-# convenience target for the above
-vm: $(VM_IMAGE)
- echo $(VM_IMAGE)
-
-# convenience target to print the filename of the test image
-print-vm:
- echo $(VM_IMAGE)
-
-# convenience target to setup all the bits needed for the integration tests
-# without actually running them
-prepare-check: $(NODE_MODULES_TEST) $(VM_IMAGE) test/common
-
-# run the browser integration tests; skip check for SELinux denials
-# this will run all tests/check-* and format them as TAP
-check: prepare-check
- TEST_AUDIT_NO_SELINUX=1 test/common/run-tests
-
-# checkout Cockpit's bots for standard test VM images and API to launch them
-# must be from main, as only that has current and existing images; but testvm.py API is stable
-# support CI testing against a bots change
-bots:
- git clone --quiet --reference-if-able $${XDG_CACHE_HOME:-$$HOME/.cache}/cockpit-project/bots https://github.com/cockpit-project/bots.git
- if [ -n "$$COCKPIT_BOTS_REF" ]; then git -C bots fetch --quiet --depth=1 origin "$$COCKPIT_BOTS_REF"; git -C bots checkout --quiet FETCH_HEAD; fi
- @echo "checked out bots/ ref $$(git -C bots rev-parse HEAD)"
-
-# checkout Cockpit's test API; this has no API stability guarantee, so check out a stable tag
-# when you start a new project, use the latest release, and update it from time to time
-test/common:
- flock Makefile sh -ec '\
- git fetch --depth=1 https://github.com/cockpit-project/cockpit.git 309; \
- git checkout --force FETCH_HEAD -- test/common; \
- git reset test/common'
-
-# checkout Cockpit's PF/React/build library; again this has no API stability guarantee, so check out a stable tag
-# TODO: replace the commit with the tag 309 once it is released, which includes cockpit.js as a ES6 module in lib/.
-$(LIB_TEST):
- flock Makefile sh -ec '\
- git fetch --depth=1 https://github.com/cockpit-project/cockpit.git 309; \
- git checkout --force FETCH_HEAD -- ../pkg/lib; \
- git reset -- ../pkg/lib'
- mv ../pkg/lib src/ && rmdir ../pkg
-
-# run 'npm install' if node_modules is missing
-# or whenever package.json changes afterwards
-$(NODE_MODULES_TEST): package.json
- # unset NODE_ENV, skips devDependencies otherwise
- env -u NODE_ENV npm install
- env -u NODE_ENV npm prune
-
-.PHONY: all clean install devel-install print-version dist node-cache rpm check vm update-po print-vm devel-uninstall
diff --git a/web/README.md b/web/README.md
index d981a61d77..200ff95e26 100644
--- a/web/README.md
+++ b/web/README.md
@@ -6,6 +6,7 @@ This Cockpit modules offers a UI to the [Agama service](file:../service). The co
## Development
+TODO: update when new way is clear how to do
There are basically two ways how to develop the Agama fronted. You can
override the original Cockpit plugins with your own code in your `$HOME` directory
or you can run a development server which works as a proxy and sends the Cockpit
@@ -16,33 +17,9 @@ The advantage of using the development server is that you can use the
feature for automatically updating the code and stylesheet in the browser
without reloading the page.
-### Overriding the Cockpit Plugin
-
-Cockpit searches for modules in the `$HOME/.local/share/cockpit` directory of the logged in user,
-which is really handy when working on a module. To make the module available to Cockpit, you can
-link your build folder (`dist`) or just rely on the `devel-install` task:
-
-```
- make devel-install
-```
-
-Then you can visit the Agama module through the following URL:
-
-http://localhost:9090/cockpit/@localhost/agama/index.html.
-
-Bear in mind that if something goes wrong while building the application (e.g., the linter fails),
-the link will not be created.
-
-To automatically rebuild the sources after any change you can run
-
-```
- npm run watch
-```
-
-*But do not forget that you have to reload the code in your browser manually after each change!*
-
### Using a development server
+TODO: update when new way is clear how to do
To start the [webpack-dev-server](https://github.com/webpack/webpack-dev-server)
use this command:
diff --git a/web/jest.config.js b/web/jest.config.js
index 87ae020f0d..18ded77fa3 100644
--- a/web/jest.config.js
+++ b/web/jest.config.js
@@ -67,7 +67,6 @@ module.exports = {
// A set of global variables that need to be available in all test environments
globals: {
- COCKPIT_TARGET_URL: "https://localhost:9090",
},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
diff --git a/web/package/_service b/web/package/_service
index 6d9bafb227..b6815b5ab4 100644
--- a/web/package/_service
+++ b/web/package/_service
@@ -8,8 +8,8 @@
web
enable
package-lock.json
- package/cockpit-agama.changes
- package/cockpit-agama.spec
+ package/agama-web-ui.changes
+ package/agama-web-ui.spec
node_modules.obscpio
diff --git a/web/package/cockpit-agama.changes b/web/package/agama-web-ui.changes
similarity index 100%
rename from web/package/cockpit-agama.changes
rename to web/package/agama-web-ui.changes
diff --git a/web/package/cockpit-agama.spec b/web/package/agama-web-ui.spec
similarity index 86%
rename from web/package/cockpit-agama.spec
rename to web/package/agama-web-ui.spec
index 382cdeb1eb..77b855c522 100644
--- a/web/package/cockpit-agama.spec
+++ b/web/package/agama-web-ui.spec
@@ -16,10 +16,10 @@
#
-Name: cockpit-agama
+Name: agama-web-ui
Version: 0
Release: 0
-Summary: Cockpit module for Agama
+Summary: Web UI for Agama installer
License: GPL-2.0-only
URL: https://github.com/openSUSE/agama
# source_validator insists that if obscpio has no version then
@@ -30,14 +30,11 @@ Source11: node_modules.spec.inc
Source12: node_modules.sums
%include %_sourcedir/node_modules.spec.inc
BuildArch: noarch
-Requires: cockpit
-BuildRequires: cockpit
-BuildRequires: cockpit-devel >= 243
BuildRequires: local-npm-registry
BuildRequires: appstream-glib
%description
-Cockpit module for the experimental Agama installer.
+Agama web UI for the experimental Agama installer.
%prep
%autosetup -p1 -n agama
@@ -45,7 +42,6 @@ rm -f package-lock.json
local-npm-registry %{_sourcedir} install --with=dev --legacy-peer-deps || ( find ~/.npm/_logs -name '*-debug.log' -print0 | xargs -0 cat; false)
%build
-# cp -r %{_datadir}/cockpit/devel/lib src/lib
NODE_ENV="production" npm run build
%install
diff --git a/web/src/DevServerWrapper.jsx b/web/src/DevServerWrapper.jsx
deleted file mode 100644
index 456b9c24f1..0000000000
--- a/web/src/DevServerWrapper.jsx
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (c) [2023] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React, { useEffect, useRef, useState } from "react";
-import {
- Button,
- Text,
- EmptyState, EmptyStateBody, EmptyStateFooter, EmptyStateHeader, EmptyStateIcon
-} from "@patternfly/react-core";
-import { Center, Icon, Loading } from "~/components/layout";
-import { _ } from "~/i18n";
-
-// path to any internal Cockpit component to force displaying the login dialog
-const loginPath = "/cockpit/@localhost/system/terminal.html";
-// id of the password field in the login dialog
-const loginId = "login-password-input";
-
-const ErrorIcon = () => ;
-
-/**
- * This is a helper wrapper used in the development server only. It displays
- * the Cockpit login page if the user is not authenticated. After successful
- * authentication the Agama page is displayed.
- *
- * @param {React.ReactNode} [props.children] - content to display within the wrapper
- *
-*/
-export default function DevServerWrapper({ children }) {
- const [isLoading, setIsLoading] = useState(true);
- const [isAuthenticated, setIsAuthenticated] = useState(null);
- const [isError, setIsError] = useState(false);
- const iframeRef = useRef(null);
-
- useEffect(() => {
- if (!isLoading) return;
-
- // get the current login state by querying the "/cockpit/login" path
- const xhr = new XMLHttpRequest();
- xhr.ontimeout = () => {
- setIsError(true);
- setIsLoading(false);
- };
- xhr.onloadend = () => {
- // 200 = OK
- if (xhr.status === 200)
- setIsAuthenticated(true);
- // 401 = Authentication failed
- else if (xhr.status === 401)
- setIsAuthenticated(false);
- else
- setIsError(true);
-
- setIsLoading(false);
- };
- xhr.timeout = 5000;
- xhr.open("GET", "/cockpit/login");
- xhr.send();
- }, [isLoading]);
-
- if (isLoading) return ;
-
- if (isError) {
- // TRANSLATORS: error message, %s is replaced by the server URL
- const [msg1, msg2] = _("The server at %s is not reachable.").split("%s");
- return (
-
- );
- }
-
- if (isAuthenticated) {
- // just display the wrapped content
- return children;
- } else {
- // handle updating the iframe with the login form
- const onFrameLoad = () => {
- // have a full screen login form
- document.getElementById("root").style.maxInlineSize = "none";
-
- const passwordInput = iframeRef.current.contentWindow.document.getElementById(loginId);
- // reload the window so the manifests.js file referenced from the
- // index.html file is also loaded again
- if (!passwordInput) window.location.reload();
- };
-
- return ;
- }
-}
diff --git a/web/src/DevServerWrapper.test.jsx b/web/src/DevServerWrapper.test.jsx
deleted file mode 100644
index 4f42362c83..0000000000
--- a/web/src/DevServerWrapper.test.jsx
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) [2023] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React from "react";
-import { render, screen, waitFor } from "@testing-library/react";
-import { act } from "react-dom/test-utils";
-
-import DevServerWrapper from "~/DevServerWrapper";
-
-// mock XMLHttpRequest object
-const xhrMock = {
- open: jest.fn(),
- send: jest.fn(),
-};
-
-describe("DevServerWrapper", () => {
- it("displays loading content at the beginning and starts a request", async () => {
- jest.spyOn(window, 'XMLHttpRequest').mockImplementation(() => xhrMock);
-
- render();
- screen.getByText(/Loading installation environment/);
-
- expect(xhrMock.open).toBeCalledWith("GET", "/cockpit/login");
- expect(xhrMock.send).toHaveBeenCalled();
- });
-
- describe("when user is not authenticated", () => {
- const xhrMockNotAuth = {
- status: 401,
- ...xhrMock
- };
-
- beforeEach(() => {
- jest.spyOn(window, 'XMLHttpRequest').mockImplementation(() => xhrMockNotAuth);
- });
-
- it("displays the login dialog", async () => {
- const { container } = render();
- // wait until the XHR finish handler is set up
- await waitFor(() => expect(xhrMockNotAuth.onloadend).toBeDefined());
- act(() => xhrMockNotAuth.onloadend());
-
- // an iframe with Cockpit terminal application is used for logging in
- const iframe = container.querySelector("iframe");
- expect(iframe.src).toMatch(/cockpit\/@localhost\/system\/terminal.html$/);
- });
- });
-
- describe("when user is already authenticated", () => {
- const xhrMockAuth = {
- status: 200,
- ...xhrMock
- };
-
- beforeEach(() => {
- jest.spyOn(window, 'XMLHttpRequest').mockImplementation(() => xhrMockAuth);
- });
-
- it("displays the children content", async () => {
- render(Testing content);
- // wait until the XHR finish handler is set up
- await waitFor(() => expect(xhrMockAuth.onloadend).toBeDefined());
- act(() => xhrMockAuth.onloadend());
- // children are displayed
- await screen.findByText("Testing content");
- });
- });
-
- describe("when authentication status request fails", () => {
- const xhrMockError = {
- status: 500,
- ...xhrMock
- };
-
- beforeEach(() => {
- jest.spyOn(window, 'XMLHttpRequest').mockImplementation(() => xhrMockError);
- });
-
- it("displays an error message", async () => {
- render();
- // wait until the XHR finish handler is set up
- await waitFor(() => expect(xhrMockError.onloadend).toBeDefined());
- act(() => xhrMockError.onloadend());
- await screen.findByText("Cannot connect to the Cockpit server");
- });
- });
-
- describe("when authentication status request times out", () => {
- beforeEach(() => {
- jest.spyOn(window, 'XMLHttpRequest').mockImplementation(() => xhrMock);
- });
-
- it("displays an error message", async () => {
- render();
- // wait until the XHR finish handler is set up
- await waitFor(() => expect(xhrMock.ontimeout).toBeDefined());
- act(() => xhrMock.ontimeout());
- await screen.findByText("Cannot connect to the Cockpit server");
- });
- });
-});
diff --git a/web/src/components/core/DevelopmentInfo.jsx b/web/src/components/core/DevelopmentInfo.jsx
deleted file mode 100644
index d1738577cb..0000000000
--- a/web/src/components/core/DevelopmentInfo.jsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) [2023] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React from "react";
-import { _ } from "~/i18n";
-
-/**
- * Displays additional info when running in a development server
- * @component
- */
-export default function DevelopmentInfo () {
- if (!process.env.WEBPACK_SERVE) return;
-
- let cockpitServer = COCKPIT_TARGET_URL;
-
- if (COCKPIT_TARGET_URL.includes("localhost") && window.location.hostname !== "localhost") {
- const urlTarget = new URL(COCKPIT_TARGET_URL);
- const url = new URL(window.location);
- url.port = urlTarget.port;
- url.pathname = "/";
- url.search = "";
- url.hash = "";
- cockpitServer = url;
- }
-
- /* NOTE: Using rel="noreferrer" below just for pleasing eslint, since all major browser already uses noreferrer
- * implicitly when using target="_blank"
- *
- * https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer
- * https://chromestatus.com/feature/6140064063029248
- * https://blog.mozilla.org/security/2021/03/22/firefox-87-trims-http-referrers-by-default-to-protect-user-privacy/
- */
- return (
- // TRANSLATORS: label for the Cockpit web user interface, used only in
- // development mode. See https://documentation.suse.com/alp/dolomite/html/cockpit-alp-dolomite/index.html
-
- );
-}
diff --git a/web/src/components/core/DevelopmentInfo.test.jsx b/web/src/components/core/DevelopmentInfo.test.jsx
deleted file mode 100644
index 65dd5007ca..0000000000
--- a/web/src/components/core/DevelopmentInfo.test.jsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) [2023] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React from "react";
-import { screen } from "@testing-library/react";
-import { plainRender } from "~/test-utils";
-import { DevelopmentInfo } from "~/components/core";
-
-const originalEnv = process.env;
-
-describe("DevelopmentInfo", () => {
- afterEach(() => {
- process.env = originalEnv;
- });
-
- describe("when not running in development mode", () => {
- beforeEach(() => {
- process.env = {
- ...originalEnv,
- WEBPACK_SERVE: false
- };
- });
-
- it("renders nothing", () => {
- const { container } = plainRender();
- expect(container).toBeEmptyDOMElement();
- });
- });
-
- describe("when running in development mode", () => {
- beforeEach(() => {
- process.env = {
- ...originalEnv,
- WEBPACK_SERVE: true
- };
- });
-
- it("renders Cockpit server url", () => {
- plainRender();
- screen.getByText("Cockpit server:");
- });
-
- // TODO: write tests checking the right url is rendered
- });
-});
diff --git a/web/src/components/core/ShowTerminalButton.jsx b/web/src/components/core/ShowTerminalButton.jsx
index 8747605557..3334af849e 100644
--- a/web/src/components/core/ShowTerminalButton.jsx
+++ b/web/src/components/core/ShowTerminalButton.jsx
@@ -22,7 +22,6 @@
import React, { useState } from "react";
import { Button } from "@patternfly/react-core";
-import { Terminal } from "~/components/core";
import { Icon } from "~/components/layout";
import { _ } from "~/i18n";
@@ -34,7 +33,6 @@ const ShowTerminalButton = () => {
const [isTermDisplayed, setIsTermDisplayed] = useState(false);
const onClick = () => setIsTermDisplayed(true);
- const onClose = () => setIsTermDisplayed(false);
return (
<>
@@ -48,8 +46,7 @@ const ShowTerminalButton = () => {
{_("Open Terminal")}
- { isTermDisplayed &&
- }
+ { isTermDisplayed && "TODO" }
>
);
};
diff --git a/web/src/components/core/ShowTerminalButton.test.jsx b/web/src/components/core/ShowTerminalButton.test.jsx
index 0463d86a55..90cb617638 100644
--- a/web/src/components/core/ShowTerminalButton.test.jsx
+++ b/web/src/components/core/ShowTerminalButton.test.jsx
@@ -24,18 +24,16 @@ import { screen } from "@testing-library/react";
import { plainRender } from "~/test-utils";
import { ShowTerminalButton } from "~/components/core";
-jest.mock("~/components/core/Terminal", () => () =>
Terminal Mock
);
-
describe("ShowTerminalButton", () => {
it("renders a button that displays after clicking", async () => {
const { user } = plainRender();
const button = screen.getByRole("button", "Terminal");
// no terminal displayed just after the render
- expect(screen.queryByText(/Terminal Mock/)).not.toBeInTheDocument();
+ expect(screen.queryByText(/TODO/)).not.toBeInTheDocument();
await user.click(button);
// it is displayed after clicking the button
- screen.getByText(/Terminal Mock/);
+ screen.getByText(/TODO/);
});
});
diff --git a/web/src/components/core/Sidebar.jsx b/web/src/components/core/Sidebar.jsx
index 2c499c0183..e094b2c2d3 100644
--- a/web/src/components/core/Sidebar.jsx
+++ b/web/src/components/core/Sidebar.jsx
@@ -24,7 +24,6 @@ import { Icon } from "~/components/layout";
import { InstallerKeymapSwitcher, InstallerLocaleSwitcher } from "~/components/l10n";
import {
About,
- DevelopmentInfo,
Disclosure,
// FIXME: unify names here by renaming LogsButton -> LogButton or ShowLogButton -> ShowLogsButton
LogsButton,
@@ -157,7 +156,6 @@ export default function Sidebar ({ children, isOpen, onClose = noop }) {
{_("Close")}
-
);
diff --git a/web/src/components/core/Sidebar.test.jsx b/web/src/components/core/Sidebar.test.jsx
index 5d714ea32d..f2a9c26c2a 100644
--- a/web/src/components/core/Sidebar.test.jsx
+++ b/web/src/components/core/Sidebar.test.jsx
@@ -26,7 +26,6 @@ import { If, Sidebar } from "~/components/core";
// Mock some components
jest.mock("~/components/core/About", () => () =>
);
@@ -55,7 +54,6 @@ it("renders expected options", () => {
screen.getByText("ShowLogButton mock");
screen.getByText("ShowTerminalButton mock");
screen.getByText("About link mock");
- screen.getByText("DevelopmentInfo mock");
});
it("renders given children", () => {
diff --git a/web/src/components/core/Terminal.jsx b/web/src/components/core/Terminal.jsx
deleted file mode 100644
index c07e26ad2d..0000000000
--- a/web/src/components/core/Terminal.jsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) [2023] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React, { useState } from "react";
-import { Popup } from "~/components/core";
-import { _ } from "~/i18n";
-
-export default function Terminal({ onCloseCallback }) {
- // the popup is visible
- const [isOpen, setIsOpen] = useState(true);
-
- const close = () => {
- setIsOpen(false);
- if (onCloseCallback) onCloseCallback();
- };
-
- // embed the cockpit terminal into an iframe, see
- // https://cockpit-project.org/guide/latest/embedding.html#embedding-components
- // https://cockpit-project.org/guide/latest/api-terminal-html.html
- return (
-
-
-
-
-
- {_("Close")}
-
-
- );
-}
diff --git a/web/src/components/core/Terminal.test.jsx b/web/src/components/core/Terminal.test.jsx
deleted file mode 100644
index 3e25a76f0c..0000000000
--- a/web/src/components/core/Terminal.test.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) [2023] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React from "react";
-
-import { screen, waitFor, within } from "@testing-library/react";
-import { plainRender } from "~/test-utils";
-import { Terminal } from "~/components/core";
-
-describe("Terminal", () => {
- it("displays the cockpit terminal in an iframe", async () => {
- plainRender();
- const dialog = await screen.findByRole("dialog");
- const iframe = dialog.querySelector("iframe");
- expect(iframe.src).toMatch(/cockpit\/@localhost\/system\/terminal.html/);
- });
-
- it("closes the popup after clicking the close button", async () => {
- const { user } = plainRender();
- const dialog = await screen.findByRole("dialog");
- const closeButton = within(dialog).getByRole("button", { name: /Close/i });
-
- await user.click(closeButton);
- await waitFor(() => {
- expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
- });
- });
-
- it("triggers the onCloseCallback after clicking the close button", async () => {
- const callback = jest.fn();
- const { user } = plainRender();
- const dialog = await screen.findByRole("dialog");
- const closeButton = within(dialog).getByRole("button", { name: /Close/i });
-
- await user.click(closeButton);
-
- expect(callback).toHaveBeenCalled();
- });
-});
diff --git a/web/src/components/core/index.js b/web/src/components/core/index.js
index 0213c66215..ee024a4417 100644
--- a/web/src/components/core/index.js
+++ b/web/src/components/core/index.js
@@ -49,11 +49,9 @@ export { default as Popup } from "./Popup";
export { default as ProgressReport } from "./ProgressReport";
export { default as ProgressText } from "./ProgressText";
export { default as ValidationErrors } from "./ValidationErrors";
-export { default as Terminal } from "./Terminal";
export { default as Tip } from "./Tip";
export { default as ShowTerminalButton } from "./ShowTerminalButton";
export { default as NumericTextInput } from "./NumericTextInput";
export { default as PasswordInput } from "./PasswordInput";
-export { default as DevelopmentInfo } from "./DevelopmentInfo";
export { default as Selector } from "./Selector";
export { default as OptionsPicker } from "./OptionsPicker";
diff --git a/web/src/index.js b/web/src/index.js
index 1762013289..4a0d97ab2e 100644
--- a/web/src/index.js
+++ b/web/src/index.js
@@ -33,7 +33,6 @@ import "@patternfly/patternfly/patternfly-base.scss";
import App from "~/App";
import Main from "~/Main";
-import DevServerWrapper from "~/DevServerWrapper";
import { OverviewPage } from "~/components/overview";
import { ProductPage, ProductSelectionPage } from "~/components/product";
import { SoftwarePage } from "~/components/software";
@@ -54,40 +53,30 @@ import { NetworkPage } from "~/components/network";
*/
import "~/assets/styles/index.scss";
-/**
- * When running in the development server add a special login wrapper which
- * checks whether the user is authenticated. When building the code outside
- * the development server an empty fragment (<>>) is used which is no-op.
- * In the production builds the DevServerWrapper code is completely omitted.
- */
-const LoginWrapper = (process.env.WEBPACK_SERVE) ? DevServerWrapper : React.Fragment;
-
const container = document.getElementById("root");
const root = createRoot(container);
root.render(
-
-
-
-
- }>
- }>
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
-
- } />
+
+
+
+ }>
+ }>
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
-
-
-
-
+ } />
+
+
+
+
);
diff --git a/web/src/lib/cockpit-rsync-plugin.js b/web/src/lib/cockpit-rsync-plugin.js
deleted file mode 100644
index 507c0176c8..0000000000
--- a/web/src/lib/cockpit-rsync-plugin.js
+++ /dev/null
@@ -1,32 +0,0 @@
-const child_process = require("child_process");
-
-module.exports = class {
- constructor(options) {
- if (!options)
- options = {};
- this.dest = options.dest || "";
- this.source = options.source || "dist/";
-
- // ensure the target directory exists
- if (process.env.RSYNC)
- child_process.spawnSync("ssh", [process.env.RSYNC, "mkdir", "-p", "/usr/local/share/cockpit/"], { stdio: "inherit" });
- }
-
- apply(compiler) {
- compiler.hooks.afterEmit.tapAsync('WebpackHookPlugin', (compilation, callback) => {
- if (process.env.RSYNC) {
- const proc = child_process.spawn("rsync", ["--recursive", "--info=PROGRESS2", "--delete",
- this.source, process.env.RSYNC + ":/usr/local/share/cockpit/" + this.dest], { stdio: "inherit" });
- proc.on('close', (code) => {
- if (code !== 0) {
- process.exit(1);
- } else {
- callback();
- }
- });
- } else {
- callback();
- }
- });
- }
-};
diff --git a/web/src/lib/webpack-po-handler.js b/web/src/lib/webpack-po-handler.js
deleted file mode 100644
index 78a26f216a..0000000000
--- a/web/src/lib/webpack-po-handler.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const fs = require("fs");
-const path = require("path");
-
-// Cockpit internally returns the "po..js" file content for the
-// "po.js" request, reimplement it with a simple redirection (the JS file
-// only exists in the webpack memory, we cannot read it from disk)
-//
-// This function processes the webpack HTTP request.
-//
-// @param req HTTP request
-// @param res HTTP response
-module.exports = function (req, res) {
- // the regexp was taken from the original Cockpit code :-)
- const language = req.headers.cookie.replace(/(?:(?:^|.*;\s*)CockpitLang\s*=\s*([^;]*).*$)|^.*$/, "$1") || "";
- // the cookie uses "pt-br" format while the PO file is "pt_BR" :-/
- let [lang, country] = language.split("-");
- country = country?.toUpperCase();
-
- // first check the full locale ("pt_BR") PO file
- if (fs.existsSync(path.join(__dirname, "..", "..", "po", `${lang}_${country}.po`))) {
- res.redirect(`/po.${lang}_${country}.js`);
- } else {
- // then check the language part only ("pt") PO file
- if (fs.existsSync(path.join(__dirname, "..", "..", "po", `${lang}.po`))) {
- res.redirect(`/po.${lang}.js`);
- } else {
- if (lang !== "en") console.log(`translation "${language}" not found`);
- // Cockpit returns an empty script if the translation file is missing
- res.set("Content-Type", "application/javascript");
- res.send("");
- }
- }
-};
diff --git a/web/src/utils.js b/web/src/utils.js
index 5969268cf1..5197d8ee1f 100644
--- a/web/src/utils.js
+++ b/web/src/utils.js
@@ -284,9 +284,7 @@ const localConnection = (location = window.location) => {
// forced local behavior
if (process.env.LOCAL_CONNECTION === "1") return true;
- // when running in a development server use the COCKPIT_TARGET_URL value
- // (a proxy is used) otherwise use the page URL from the browser
- const hostname = process.env.WEBPACK_SERVE ? (new URL(COCKPIT_TARGET_URL)).hostname : location.hostname;
+ const hostname = location.hostname;
// using the loopback device? (hostname or IP address)
return hostname === "localhost" || hostname.startsWith("127.");
diff --git a/web/webpack.config.js b/web/webpack.config.js
index 593383066d..cf50d696a0 100644
--- a/web/webpack.config.js
+++ b/web/webpack.config.js
@@ -8,13 +8,10 @@ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const HtmlMinimizerPlugin = require("html-minimizer-webpack-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const ESLintPlugin = require('eslint-webpack-plugin');
-const CockpitPoPlugin = require("./src/lib/cockpit-po-plugin");
-const CockpitRsyncPlugin = require("./src/lib/cockpit-rsync-plugin");
const StylelintPlugin = require('stylelint-webpack-plugin');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const webpack = require('webpack');
-const po_handler = require("./src/lib/webpack-po-handler");
const manifests_handler = require("./src/lib/webpack-manifests-handler");
/* A standard nodejs and webpack pattern */
@@ -46,19 +43,12 @@ const copy_files = [
const plugins = [
new Copy({ patterns: copy_files }),
new Extract({ filename: "[name].css" }),
- new CockpitPoPlugin(),
- new CockpitRsyncPlugin({ dest: packageJson.name }),
development && new ReactRefreshWebpackPlugin({ overlay: false }),
// replace the "process.env.WEBPACK_SERVE" text in the source code by
// the current value of the environment variable, that variable is set to
// "true" when running the development server ("npm run server")
// https://webpack.js.org/plugins/environment-plugin/
new webpack.EnvironmentPlugin({ WEBPACK_SERVE: null, LOCAL_CONNECTION: null }),
- // similarly for a non-environment value
- // https://webpack.js.org/plugins/define-plugin/
- // but because ESlint runs *before* the DefinePlugin we need to
- // add it as a global variable in .eslintrc.json config file
- new webpack.DefinePlugin({ COCKPIT_TARGET_URL: JSON.stringify(cockpitTarget) }),
].filter(Boolean);
if (eslint) {
@@ -102,14 +92,7 @@ module.exports = {
// additionally watch these files for changes
watchFiles: ["./src/manifest.json", "./po/*.po"],
proxy: {
- // forward all cockpit connections to a real Cockpit instance
- "/cockpit": {
- target: cockpitTarget,
- // redirect also the websocket connections
- ws: true,
- // ignore SSL problems (self-signed certificate)
- secure: false,
- },
+ // TODO: modify it to not depend on cockpit
// forward the manifests.js request and patch the response with the
// current Agama manifest from the ./src/manifest.json file
"/manifests.js": {
@@ -126,12 +109,6 @@ module.exports = {
// hot replacement does not support wss:// transport when running over https://,
// as a workaround use sockjs (which uses standard https:// protocol)
webSocketServer: "sockjs",
-
- // Cockpit handles the "po.js" requests specially
- setupMiddlewares: (middlewares, devServer) => {
- devServer.app.get("/po.js", po_handler);
- return middlewares;
- }
},
devtool: "source-map",
stats: "errors-warnings",