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
.tsxfiles should only export one component via a named export - Component props are typed as
interfaceand 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
-
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. -
Using the Feature Toggle in Code:
Use theuseFeatureTogglehook to check if a feature is enabled. This hook also considers user permissions, such as theALPHA_FEATUREusage 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>;
}