Skip to content

Numera UI

Development

Prerequisites

Setup

Clone the PIT-Numera/ui repository.

git clone git@github.com:PIT-Numera/ui.git

Switch to projects node version:

nvm use

or use nvms Deeper Shell Integration.

Authenticate custom npm-registry

You need to generate a github access-token via https://github.com/settings/tokens (you can use your existing maven-token or generate a new one with at least rights for "read:packages")

npm login --scope=@pit-numera --registry=https://npm.pkg.github.com
> Username: USERNAME
> Password: TOKEN
> Email: PUBLIC-EMAIL-ADDRESS

Afterward pnpm install should work as well for libraries that are only accessible via custom github registry.

Install dependencies

pnpm install

Read further details

Setting local environment variables

Copy apps/numera-ui/.env.example, rename it to .env.local and fill out the required variables.

Or Pull environment variables from AWS:

./scripts/pull-env.sh

This will write all required environment variables into apps/numera-ui/.env.local.

Run numera-ui locally

pnpm dev

Generate a library

To generate a non-buildable, compatible library with jest as a test runner run the following script:

./scripts/generate-lib.sh --name new-lib

Coding conventions

General

Numera UI folder structure follows the Nx Structure.

The main app (numera-ui) is located in the apps directory.

Code style rules are defined in Eslint config

Code formatting is defined in Prettier config

Identifiers

Based on: Google TypeScript Style Guide

Style Description
UpperCamelCase components, class / interface / type / enum / decorator / type parameters
lowerCamelCase variable / parameter / function / method / property / module alias
CONSTANT_CASE global constant values, enum values
kebab-case file and folder names

Folder structure

apps

numera-ui only contains the application boilerplate (authentication, route definitions, assets, ...)

Every feature should be implemented as described in the following.

libs

All features are living in the libs directory and are named by feat-{name}.

New features are generated with Nx Generators:

./scripts/generate-lib.sh feat-{name} --name "feat-custom-feature"

Features only depend on shared libraries but not on other features.

The ui-components folder holds reusable components that could be used in multiple libraries. For every component there should be corresponding Storybook file.

Features folder structure:

libs/
└── feat-[name]/
    └── src/
        ├── components
        ├── hooks
        ├── pages
        ├── state
        ├── utils
        ├── routes.tsx
        └── index.ts

Every exported member of a feature is defined in the features index.ts file.

Feature routes are defined in the features routes.tsx.

Every folder defines its exported members in a index.ts barrel file:

components/
├── card-button/
│   ├── card-button.tsx
│   ├── card-button-groupe.tsx
│   └── index.ts
├── dialog/
│   ├── dialog.tsx
│   ├── dialog-container.tsx
│   └── index.ts
└── index.ts
Refactor a component into a lib
./scripts/refactor-into-lib.sh --name "feat-custom-feature" libs/feat-statistic/src/components/custom-feature

This will run nx g @nx/react:lib and git mv the corresponding directory into the newly generated libs src folder.

Components

  • Components .tsx files should only export one component via a named export
  • Component props are typed as interface and follow the naming of: {ComponentName}Props
  • Props interfaces should be exported

Example:

export interface NumeraComponentProps {
  label: string;
}

export function NumeraComponent({ label }: NumeraComponentProps) {
  return <div>{label}</div>;
}

Components can have their own folder structures with nested hooks and utils folders:

components/
└── card-button/
    ├── hooks
    ├── utils
    ├── card-button.tsx
    ├── card-button-groupe.tsx
    └── index.ts

Classnames and Styles

Styles without any variant:

<div className="flex">{children}</div>

Combine className from multiple sources:

<div className={clsx('flex', className)}>{children}</div>

Style variants that change depending on props.

<div
  className={clsx('flex', {
    'items-center': position === 'center',
    'text-red-400': isError,
  })}
>
  {children}
</div>

Note that we keep the default styles as the first argument of clsx.

Feature toggles

Feature toggles in Numera UI are managed using Unleash. They allow us to enable or disable features dynamically without deploying new code.

Creating a Feature Toggle

  1. Create the toggle in Unleash: Log in to the Unleash dashboard and create a new feature toggle. Assign it a unique name (e.g., new-feature-toggle) and configure its activation strategies as needed.

  2. Using the Feature Toggle in Code:
    Use the useFeatureToggle hook to check if a feature is enabled. This hook also considers user permissions, such as the ALPHA_FEATURE usage right.

Example:

import { useFeatureToggle } from '@pit-numera/feat-user-management';

export function MyComponent() {
  const isFeatureEnabled = useFeatureToggle('new-feature-toggle');

  if (!isFeatureEnabled) {
    return null; // Hide or disable the feature
  }

  return <div>Feature is enabled!</div>;
}