UI
This is the frontend for the xpanse project which allows cloud service providers to register managed services to the service catalog and also for end users to deploy services from the service catalog and manage them.
Application Stack
Project is built using ReactJS
library. As we use TypeScript
here, we must ensure all objects have its type explicit
defined.
GUI components are built using antd
library.
Authentication and Authorization
Auth can be controlled by VITE_APP_AUTH_DISABLED
configuration property.
This property is also already configured with appropriate values in different configuration files.
Disable
When we start the UI with the default run command npm run start
,
then the UI will start with no authentication and authorization.
This must be used only for testing and development purposes.
When authentication and authorization is disabled, the test user will then have all roles by default.
OAuth
Authentication and authorization are protected by an OAuth provider.
The default implementation uses Zitadel
as the OAuth provider.
Zitadel Configuration
Before we can start using the UI, we must ensure Zitadel
instance that we consider using,
has all the required configuration. Details can be found here.
For local environments, the access_tokens
are stored with in the browser storage.
This isn't safe, but it's enough for non-production environments and for debugging purposes.
For production environments, we must use Service Workers
which will block anyone from accessing the token.
This can be enabled by making the following configurations.
VITE_APP_AUTH_USE_SERVICE_WORKER_ONLY=true
and the file OidcTrustedDomains.js must be updated with correct information.
oidcDomains
must have the identity provider URL and accessTokenDomains
must have the xpanse API server URL.
If the same must be used with our official docker images, then this file need not be touched. It will be automatically set from the environment variables.
Configuration Properties
All required configuration parameters must be added to .env file here. Even if we don't have a valid default value, we must just add empty value. This file serves as a reference to all required properties.
Since React is compiled to a static app, all configuration values can be seen directly in the browser too. Therefore, no secure configurations such as passwords, keys, etc. must be added here.
Setting Configuration Values
.env Files
- Set values in the .env files.
All default values are set in .env files.
These are automatically loaded by
React
and there is no need to do anything for this to be loaded. - For non-default properties or to override the values is .env, we can set the values in new .env files and load them
using
env-cmd
framework which will automatically inject the variables. Example can be found here
.env files must be used only for default configurations or for development environment configurations values.
Environment Variables
All variables can be overridden by setting environment variables and then running the npm run start
for development or
with docker run
for production.
Getting Configuration Values
We've a custom implementation which reads the configuration from all sources and provides a unified configuration map. Only this must be used for reading configuration from the React app.
Implementation can be found here.
Starting local development server
In the project directory, you can run the below command to start the local development server. This also additionally
needs nodejs
to be installed on the development machine.
No Auth
To start local development server without any auth, use the below command.
$ npm run start
Local OAuth
To start local development server with local OAuth server,
then update the VITE_APP_ZITADEL_CLIENT_ID
value in the .env.zitadel-local
fie and
then start the server with below command.
$ npm run start-with-zitadel-local
Testbed OAuth
If you wish to use our central Zitadel testbed instance, then simply start the application with the below command. For this you would need an account on our testbed instance.
$ npm run start-with-zitadel-testbed
Open http://localhost:3000 to view it in the browser.
Static Code Analysis
We use eslint
and knip
to statically analyze code.
Always run the below command locally to ensure the changes made results in no errors. This will also validate the code
format.
In case of any errors, the CI pipeline will fail when a PR is opened.
npx eslint . --ext .js,.jsx,.ts,.tsx --config package.json --max-warnings=0
npx knip
Code Formatting
We use prettier
to format our UI code. To auto format the code, you can run the below command.
npx prettier --config .prettierrc --write .
Generate Rest Client for xpanse API
We use the OpenAPI generator to generate data models and rest client from the OpenAPI JSON file. The following steps must be followed to generate a new client and data models whenever there is a new version if the swagger JSON.
- Copy the OpenAPI file to OpenAPI JSON File
- Run the code generator as below
This script will generate all required models and client, add license headers and format newly generated files.
./scripts/generate_api_client.sh
Build for production
The only recommended way to run UI in production is to use the docker image
Docker Image
Docker image for the UI project is based on NGINX base image. This is because the project only serves static content.
As part of our UI release process, we deliver our official images to GitHub packages. All available images can be found here.
Run UI Container
Container runs the application on port 3000
by default and exposes the UI using HTTP.
We must use another SSL load balancer to expose the UI for end users.
Production configuration values must be passed as environment variables to docker run for the below vars using -e
option.
VITE_APP_ZITADEL_AUTHORITY_NAME # URL for the Oauth provider
VITE_APP_ZITADEL_CLIENT_ID # Client ID provided by the Oauth provider for UI
VITE_APP_XPANSE_API_URL # xpanse API URL
VITE_APP_AUTH_USE_SERVICE_WORKER_ONLY=true # for production. Otherwise, this step config can be ignored.
docker pull ghcr.io/eclipse-xpanse/xpanse-ui:${version}
docker run -d --name ui xpanse-ui
Application Logs
All logs from NGINX are routed to stdout by default. Using the below command, all application logs can be viewed.
docker logs ui
Non production environments without HTTPS
The OAuth client libraries used by the UI are highly secure and don't allow using plain HTTP except for localhost
.
For all other test purposes when there is a necessity to use HTTP together with an IP or host name that's not localhost
,
then the browser configuration must be changed as below to consider that IP or host name as a secure origin.
- Go to chrome://flags/#unsafely-treat-insecure-origin-as-secure.
- Add the origin which you want to treat as secure that is, http://example.com:8080.
- Restart chrome.
Unit and Integration Tests
We use playwright to write unit and integration tests for the UI components. Please consider the following points in writing tests
- Use Page Object Models (POM) for each component.
- Consider stable locators for elements.
- Use the default codegen and mock recorder from playwright to ensure faster development.
Running tests
npx playwright test
Run Tests with inbuilt UI - Necessary for debugging
npx playwright test --ui
Generating locators and actions for tests
Use playwright's inbuilt codegen to generate locators for DOM elements. Start UI app locally first and then run
npx playwright codegen http://localhost:3000
Mocking API responses
It's easier to capture API responses to mock them after that in the unit tests rather than manually creating mock.
This command will start the browser, and then we must perform actions on the UI that are necessary to be mocked. It will then record the API responses into test.har which can be then used in the tests.
npx playwright open --save-har=test.har --save-har-glob="**/xpanse/**" http://localhost:3000