ort-server/ui at main · eclipse-apoapsis/ort-server · GitHub
Skip to content

Latest commit

 

History

History

ui

README.md

Web UI

This directory contains the web UI for ORT Server.

Architecture

The UI is a React application and uses Vite as the build tool and pnpm as the package manager.

React Compiler

The build runs React Compiler through @rolldown/plugin-babel, configured in vite.config.ts. It memoizes components and hooks, so new code usually does not need useMemo, useCallback or memo(). Keep a manual useMemo or useCallback where a value must keep its identity while the compiler would see a changed input, such as a new object with the same contents, and say why in a comment.

  • The compiler silently skips a component it cannot handle, and pnpm lint does not report every reason for a skip; unsupported syntax such as try … finally is not reported. A skipped component also hides its other compiler lint findings.
  • The compiler reuses a value computed from an object for as long as the object stays the same. A component that reads state through an object whose identity does not change when the state does, such as TanStack Table rows and columns, would show outdated content. Either read the state through an API that re-renders the component, such as table.Subscribe, or leave the component out with a 'use no memo' directive and a comment saying why.
  • With React Hook Form, a component that receives the result of useForm from its parent must subscribe to what it shows: read values with useWatch and form state with useFormState. watch() is rejected by lint. Leaving out only the child does not help, because the compiled parent keeps reusing the child's element. If the child cannot subscribe, leave out the parent instead, with a comment saying why. Call getValues() only in event handlers and effects.
  • Define components at module level. For a component defined inside another function, the compiler can move callbacks out of the function, where they no longer see its variables.
  • Code is compiled only in tests that run in the jsdom environment (// @vitest-environment jsdom).

Prerequisites

By default, the UI expects ORT Server to be running locally.

If there are no local changes, the fastest way to get started is to use published ORT Server images for UI development. To do so, run the following commands from the project root directory:

$ docker compose pull # Ensure that all images are up-to-date.
$ docker compose up -d # Bring services up in detached mode.

If you depend on local changes to the Kotlin backend, you instead need to build the images locally:

$ ./gradlew :buildAllImages # Build all images locally.
$ docker compose up -d # Bring services up in detached mode.

Next, ensure that the API definitions are up to date by running:

$ ./gradlew :core:generateOpenApiSpec
$ pnpm -C ui install
$ pnpm -C ui build

Development

For interactive UI development with live-preview in the browser follow these steps:

  1. Run pnpm -C ui dev.
  2. Ctrl-click the shown http://localhost:5173/ link.
  3. Log in via Keycloak (use "admin" / "admin" as username / password).

API Changes

If changes to the API were done during development, these are the minimum commands to rerun to reflect the changes (again from the project root):

$ ./gradlew -PdockerImagePrefix=ghcr.io/eclipse-apoapsis/ -PdockerImageTag=main :core:tinyJibDocker
$ docker compose up -d core
$ ./gradlew :core:generateOpenApiSpec
$ pnpm -C ui generate:api

Unit and component tests

After completing the normal UI setup above, run the Vitest suite from the repository root:

$ pnpm -C ui test --run
$ pnpm -C ui test:coverage

These tests use local fixtures and mocks and do not require running Docker services or installing Playwright browsers. Coverage is disabled for ordinary test runs. The coverage command prints statement, branch, function, and line totals and writes reports to ui/coverage/:

  • Open ui/coverage/index.html in a browser to inspect coverage by source file.
  • ui/coverage/coverage-summary.json contains machine-readable totals.
  • ui/coverage/lcov.info can be used by coverage reporting tools.

Reports include untested TypeScript and TSX source files, but exclude generated API code, the generated route tree, and type declarations. Generated reports are ignored by version control, ESLint, and Prettier. No coverage threshold is enforced.

Coverage in pull requests

The "UI Coverage" workflow measures UI test coverage for every pull request, and the "Report UI Coverage" workflow posts the result as a comment on it once "UI Coverage" has finished. This also works for pull requests from forks. Each new push updates the same comment. The comment shows the coverage of the pull request and, below each value, the change against the commit of the target branch the pull request is based on. The change is labelled pp, which means percentage points. The pull request is measured as GitHub merges it into the target branch for testing, so the change comes from the pull request only, even if the branch is behind the target branch. The footer names the last commit of the pull request.

The status icon of each metric shows its coverage level: 🔴 below 50%, 🟠 from 50% and 🟢 from 80%. These thresholds are a trial and only colour the report.

Coverage is for information only: a drop in coverage does not fail the build, and "UI Coverage" is not a required check. Measuring coverage makes the tests slower, so a test can occasionally hit its time limit and fail "UI Coverage" without blocking the merge. If measuring either coverage fails, the comment is not updated and still shows the numbers of an earlier commit, named in its footer.

The full HTML and LCOV reports can be downloaded from the "UI Coverage" run. Small changes can come from code that depends on the current time, and the React Compiler can change function and branch counts, so look at the reports before reading too much into a change of a few hundredths.

e2e tests

To run the Playwright e2e tests locally, first start core service (also starts keycloak, postgres and rabbitmq) and dev UI, then run the tests:

$ docker compose up -d core
$ cd ui
$ pnpm dev
$ pnpm test:e2e

Docker

The Docker image for the UI is built as part of the buildAllImages Gradle task. To build it manually, run the following steps from the root of the repository:

  • Build the OpenAPI specification: ./gradlew :core:generateOpenApiSpec
  • Build the Docker image: docker build -t ort-server-ui -f ui/docker/UI.Dockerfile ui

To run the Docker image, use the following command:

docker run --rm -p 8082:8080 ort-server-ui

The Docker image can be configured by the following environment variables:

Variable Default Description
UI_API_URL http://localhost:8080 The URL of the ORT Server API.
UI_URL http://localhost:8082 The URL of the UI.
UI_BASEPATH / The base path of the UI.
UI_AUTHORITY http://localhost:8081/realms/master The URL of the Keycloak realm.
UI_CLIENT_ID ort-server-ui The client ID of the UI in Keycloak.

Read-only Root Filesystem

The image supports running with a read-only root filesystem (e.g. in OpenShift). The following directories must be writable and should be mounted as emptyDir volumes:

Path Purpose
/etc/nginx/conf.d Generated nginx config.
/var/cache/nginx nginx cache.
/var/log/nginx nginx logs.
/usr/share/nginx/html Serving directory populated at startup.
/var/run nginx PID file.