diff --git a/nixos/tests/lxd/ui.nix b/nixos/tests/lxd/ui.nix index 86cb30d8c2b6..ff651725ba70 100644 --- a/nixos/tests/lxd/ui.nix +++ b/nixos/tests/lxd/ui.nix @@ -11,9 +11,37 @@ import ../make-test-python.nix ({ pkgs, lib, ... }: { lxd.ui.enable = true; }; - environment.systemPackages = [ pkgs.curl ]; + environment.systemPackages = + let + seleniumScript = pkgs.writers.writePython3Bin "selenium-script" + { + libraries = with pkgs.python3Packages; [ selenium ]; + } '' + from selenium import webdriver + from selenium.webdriver.common.by import By + from selenium.webdriver.firefox.options import Options + from selenium.webdriver.support.ui import WebDriverWait + + options = Options() + options.add_argument("--headless") + service = webdriver.FirefoxService(executable_path="${lib.getExe pkgs.geckodriver}") # noqa: E501 + + driver = webdriver.Firefox(options=options, service=service) + driver.implicitly_wait(10) + driver.get("https://localhost:8443/ui") + + wait = WebDriverWait(driver, 60) + + assert len(driver.find_elements(By.CLASS_NAME, "l-application")) > 0 + assert len(driver.find_elements(By.CLASS_NAME, "l-navigation__drawer")) > 0 + + driver.close() + ''; + in + with pkgs; [ curl firefox-unwrapped geckodriver seleniumScript ]; }; + testScript = '' machine.wait_for_unit("sockets.target") machine.wait_for_unit("lxd.service") @@ -31,5 +59,8 @@ import ../make-test-python.nix ({ pkgs, lib, ... }: { # Ensure the endpoint returns an HTML page with 'LXD UI' in the title machine.succeed("curl -kLs https://localhost:8443/ui | grep 'LXD UI'") + + # Ensure the application is actually rendered by the Javascript + machine.succeed("PYTHONUNBUFFERED=1 selenium-script") ''; }) diff --git a/pkgs/tools/admin/lxd/package.json b/pkgs/tools/admin/lxd/package.json deleted file mode 100644 index e30b269605ee..000000000000 --- a/pkgs/tools/admin/lxd/package.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "name": "lxd-ui", - "version": "0.0.1", - "author": "Canonical Webteam", - "license": "LGPL-3.0-only", - "scripts": { - "clean": "rm -rf node_modules yarn-error.log *.log build/ .jekyll-metadata .bundle playwright-report test-results haproxy-local.cfg", - "build-html": "cp build/ui/index.html build/index.html", - "build": "npx vite build && yarn build-html", - "format-js-eslint": "eslint 'src/**/*.{json,jsx,tsx,ts}' 'tests/**/*.ts' --fix", - "format-js-prettier": "prettier 'src/**/*.{json,jsx,tsx,ts}' 'tests/**/*.ts' --write", - "format-js": "yarn format-js-eslint && yarn format-js-prettier", - "lint-scss": "stylelint 'src/**/*.scss'", - "lint-js-eslint": "eslint 'src/**/*.{json,tsx,ts}' 'tests/**/*.ts' .eslintrc.js babel.config.js", - "lint-js-prettier": "prettier 'src/**/*.{json,tsx,ts}' 'tests/**/*.ts' .eslintrc.js babel.config.js --check", - "lint-js": "yarn lint-js-eslint && yarn lint-js-prettier", - "hooks-add": "husky install", - "hooks-remove": "husky uninstall", - "start": "concurrently --kill-others --raw 'vite | grep -v localhost' 'yarn serve'", - "serve": "./entrypoint", - "test-js": "react-scripts test src/ --watchAll=false"}, - "dependencies": { - "@canonical/react-components": "0.47.0", - "@monaco-editor/react": "^4.4.6", - "@tanstack/react-query": "^4.14.5", - "@use-it/event-listener": "^0.1.7", - "axios": "1.3.2", - "cytoscape": "3.23.0", - "cytoscape-popper": "2.0.0", - "formik": "2.2.9", - "js-yaml": "4.1.0", - "lodash.isequal": "4.5.0", - "node-forge": "1.3.1", - "parse-prometheus-text-format": "1.1.1", - "react": "18.2.0", - "react-cytoscapejs": "2.0.0", - "react-dom": "18.2.0", - "react-router-dom": "6.6.1", - "react-scripts": "5.0.1", - "react-useportal": "^1.0.17", - "serve": "14.1.2", - "vanilla-framework": "4.3.0", - "xterm-addon-fit": "0.6.0", - "xterm-for-react": "1.0.4", - "yup": "0.32.11" - }, - "devDependencies": { - "@babel/core": "7.20.7", - "@babel/eslint-parser": "7.19.1", - "@babel/preset-env": "7.20.2", - "@babel/preset-react": "7.18.6", - "@babel/preset-typescript": "7.18.6", - "@playwright/test": "^1.29.1", - "@types/cytoscape-popper": "2.0.0", - "@types/node-forge": "1.3.1", - "@types/react": "18.0.26", - "@types/react-cytoscapejs": "1.2.2", - "@types/react-dom": "18.0.10", - "@types/react-router-dom": "5.3.3", - "@types/websocket": "1.0.5", - "@typescript-eslint/eslint-plugin": "5.48.0", - "@typescript-eslint/parser": "5.48.0", - "@vitejs/plugin-react": "^3.1.0", - "autoprefixer": "10.4.13", - "babel-loader": "9.1.0", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", - "concurrently": "7.6.0", - "css-loader": "6.7.3", - "eslint": "8.31.0", - "eslint-config-prettier": "8.6.0", - "eslint-plugin-prettier": "4.2.1", - "eslint-plugin-react": "7.31.11", - "husky": "8.0.0", - "lint-staged": "13.1.1", - "monaco-editor": "0.36.1", - "postcss": "8.4.20", - "postcss-cli": "10.1.0", - "prettier": "2.8.1", - "sass": "1.57.1", - "sass-loader": "13.2.0", - "style-loader": "3.3.1", - "stylelint": "15.10.1", - "stylelint-config-prettier": "9.0.4", - "stylelint-config-standard-scss": "6.1.0", - "stylelint-order": "5.0.0", - "stylelint-prettier": "2.0.0", - "stylelint-scss": "4.3.0", - "ts-loader": "9.4.2", - "typescript": "4.9.4", - "vite": "^4.1.0", - "vite-tsconfig-paths": "4.0.5" - }, - "lint-staged": { - "src/**/*.{json,jsx,ts,tsx}": [ - "eslint", - "prettier --check" - ], - "tests/**/*.{json,jsx,ts,tsx}": [ - "eslint", - "prettier --check" - ], - "src/**/*.scss": "stylelint" - } -} diff --git a/pkgs/tools/admin/lxd/ui.nix b/pkgs/tools/admin/lxd/ui.nix index b0582ef99969..c248199b4ad7 100644 --- a/pkgs/tools/admin/lxd/ui.nix +++ b/pkgs/tools/admin/lxd/ui.nix @@ -1,35 +1,61 @@ -{ mkYarnPackage +{ lib +, stdenv , fetchFromGitHub , fetchYarnDeps -, lib +, nodejs +, prefetch-yarn-deps +, yarn }: -mkYarnPackage rec { +stdenv.mkDerivation rec { pname = "lxd-ui"; - version = "0.2"; + version = "0.4"; src = fetchFromGitHub { owner = "canonical"; repo = "lxd-ui"; rev = "refs/tags/${version}"; - sha256 = "sha256-DygWNktangFlAqinBm6wWsRLGmX6yjhmRJ2iU0yjcgk="; + hash = "sha256-l9Fp/Vm7NxMCp5QcM8+frFyfahhPG7TyF6NhfU1SEaA="; }; - packageJSON = ./package.json; offlineCache = fetchYarnDeps { yarnLock = "${src}/yarn.lock"; - sha256 = "sha256-B1SVCViX1LEFoBLMdFk9qaoayku7Y+zU5c4JEJkLmwE="; + hash = "sha256-R6OeaBC6xBHa229YGyc2LDjjenwvS805PW8ueU/o99I="; }; + nativeBuildInputs = [ + nodejs + prefetch-yarn-deps + yarn + ]; + + configurePhase = '' + runHook preConfigure + + export HOME=$(mktemp -d) + yarn config --offline set yarn-offline-mirror "$offlineCache" + fixup-yarn-lock yarn.lock + yarn --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive install + patchShebangs node_modules + + runHook postConfigure + ''; + buildPhase = '' + runHook preBuild + yarn --offline build + + runHook postBuild ''; installPhase = '' - cp -rv deps/lxd-ui/build/ui/ $out - ''; + runHook preInstall - doDist = false; + cp -r build/ui/ $out + + runHook postInstall + ''; meta = { description = "Web user interface for LXD.";