Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions .ai/angular-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ Components rely on signals for UI updates.
Example:

@Component({
selector: 'app-counter',
changeDetection: ChangeDetectionStrategy.OnPush
selector: 'app-counter'
})
export class CounterComponent {

Expand Down Expand Up @@ -43,9 +42,35 @@ export const CounterStore = signalStore(
Usage in component:

@Component({
selector: 'app-counter',
changeDetection: ChangeDetectionStrategy.OnPush
selector: 'app-counter'
})
export class CounterComponent {
store = inject(CounterStore);
}

## UI components with optimus-ui

UI components come from `@openng/optimus-ui`, imported per-component from their subpath.

Example:

import { Component, input, output } from '@angular/core';
import { Paginator, PaginatorState } from '@openng/optimus-ui/paginator';

@Component({
selector: 'app-list',
imports: [Paginator],
template: `
<p-paginator
[first]="first()"
[rows]="rows()"
[totalRecords]="total()"
(onPageChange)="pageChange.emit($event)" />
`
})
export class ListComponent {
first = input.required<number>();
rows = input.required<number>();
total = input.required<number>();
pageChange = output<PaginatorState>();
}
13 changes: 2 additions & 11 deletions .ai/angular-rules.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Angular Rules

Framework version: Angular 21
Framework version: Angular 22

## Core rules

Expand All @@ -9,23 +9,14 @@ Framework version: Angular 21
- Prefer Angular Signals for local state.
- Avoid RxJS when Signals are sufficient.
- Use strict TypeScript typing.
- Use `@openng/optimus-ui` components for UI needs instead of building custom widgets.

## Component design

- Components must remain small and focused on UI.
- Business logic should not live inside components.
- Move reusable logic to services or pure functions.

## Change detection

- Use OnPush change detection by default.

Example:

@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})

## Dependency injection

- Avoid unnecessary services.
Expand Down
10 changes: 10 additions & 0 deletions .ai/dev-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,13 @@ pnpm test:watch
Run tests with coverage:

pnpm test:coverage

## Lint

Run ESLint:

pnpm lint

Run ESLint and automatically fix issues:

pnpm lint:fix
5 changes: 3 additions & 2 deletions .ai/project-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

## Stack

- Angular 21
- Angular 22
- Standalone components
- TypeScript strict mode
- Zoneless change detection (Zone.js disabled)
- NgRx Signal Store for application state
- Signals preferred over RxJS
- @openng/optimus-ui as UI component library (Tailwind CSS-based)
- Vitest for testing
- Node 22.13+
- Node ^22.22.3 || ^24.15.0 || >=26.0.0 (per @angular/cli's engines requirement)
- pnpm as package manager

## Architecture principles
Expand Down
10 changes: 4 additions & 6 deletions .ai/prompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ These prompt templates help guide the LLM when performing common tasks in this r

## Fix Angular test

Goal: migrate this test to Vitest.
Goal: fix this failing or broken test.

Constraints:

- do not change business logic
- replace Jasmine APIs with Vitest equivalents
- replace `jasmine.createSpy` with `vi.fn`
- replace `spyOn` with `vi.spyOn`
- use Vitest APIs (`vi.fn`, `vi.spyOn`, etc.)
- keep TestBed only if Angular integration is required

## Refactor Angular component
Expand All @@ -20,12 +18,12 @@ Goal: simplify this component.

Constraints:

- Angular 21
- Angular 22
- standalone components only
- do not introduce NgModules
- move business logic outside components when possible
- avoid RxJS if Angular Signals are sufficient
- keep change detection strategy OnPush
- use `@openng/optimus-ui` components instead of custom widgets

## Improve typing

Expand Down
33 changes: 17 additions & 16 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,26 @@ on: [push, pull_request]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [22.13.x, 24.0.x]
node-version: ['^24.15.0', '^26.0.0']

steps:
- uses: actions/checkout@v6
- name: Use pnpm
uses: pnpm/action-setup@v4
with:
version: 11.17.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: pnpm
- name: install package
run: pnpm install --frozen-lockfile
- name: run tests
run: pnpm test
- uses: actions/checkout@v7
- name: Use pnpm
uses: pnpm/action-setup@v6
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}
cache: pnpm
- name: install package
run: pnpm install --frozen-lockfile
- name: run lint
run: pnpm lint
- name: run build
run: pnpm build
- name: run tests
run: pnpm test
12 changes: 12 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"printWidth": 100,
"singleQuote": true,
"overrides": [
{
"files": "*.html",
"options": {
"parser": "angular"
}
}
]
}
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
@.ai/angular-rules.md
@.ai/angular-patterns.md
@.ai/dev-commands.md
@.ai/prompts.md
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pnpm install

## Bibliothèques dans ce projet

- [Angular 21](https://angular.dev)
- [Angular 22](https://angular.dev)
- [NgRx Signal Store](https://ngrx.io/guide/signals)
- [Tailwind CSS](https://tailwindcss.com)
- [Optimus UI](https://optimus.openng.org/)
Expand All @@ -22,7 +22,33 @@ pnpm install
Pour démarrer le projet

```bash
pnpm run start
pnpm start
```

Pour démarrer le projet avec des données mockées :

```bash
pnpm start_mock
```

Une fois le serveur lancé, ouvrez votre navigateur et rendez-vous à l'adresse `http://localhost:4200/`. L'application se rechargera automatiquement chaque fois que vous modifierez l'un des fichiers source.

## Tests

Lancer la suite de tests :

```bash
pnpm test
```

Lancer les tests en mode watch :

```bash
pnpm test:watch
```

Lancer les tests avec la couverture de code :

```bash
pnpm test:coverage
```
49 changes: 49 additions & 0 deletions eslint.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import eslint from '@eslint/js';
import angular from 'angular-eslint';
import { defineConfig } from 'eslint/config';
import simpleImportSort from 'eslint-plugin-simple-import-sort';
import tseslint from 'typescript-eslint';

export default defineConfig([
{
ignores: ['dist/**', 'coverage/**'],
},
{
files: ['**/*.ts'],
extends: [
eslint.configs.recommended,
tseslint.configs.recommended,
tseslint.configs.stylistic,
angular.configs.tsRecommended,
],
processor: angular.processInlineTemplates,
plugins: {
'simple-import-sort': simpleImportSort,
},
rules: {
'@angular-eslint/directive-selector': [
'error',
{
type: 'attribute',
prefix: 'app',
style: 'camelCase',
},
],
'@angular-eslint/component-selector': [
'error',
{
type: 'element',
prefix: 'app',
style: 'kebab-case',
},
],
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
},
},
{
files: ['**/*.html'],
extends: [angular.configs.templateRecommended, angular.configs.templateAccessibility],
rules: {},
},
]);
71 changes: 34 additions & 37 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,47 @@
"watch": "ng build --watch --configuration development",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
},
"prettier": {
"printWidth": 100,
"singleQuote": true,
"overrides": [
{
"files": "*.html",
"options": {
"parser": "angular"
}
}
]
"test:coverage": "vitest run --coverage",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"private": true,
"packageManager": "[email protected]",
"dependencies": {
"@angular/common": "^21.2.19",
"@angular/compiler": "^21.2.19",
"@angular/core": "^21.2.19",
"@angular/forms": "^21.2.19",
"@angular/platform-browser": "^21.2.19",
"@angular/router": "^21.2.19",
"@ngrx/signals": "^21.1.1",
"@angular/common": "^22.1.3",
"@angular/compiler": "^22.1.3",
"@angular/core": "^22.1.3",
"@angular/forms": "^22.1.3",
"@angular/platform-browser": "^22.1.3",
"@angular/router": "^22.1.3",
"@ngrx/signals": "^22.0.0",
"@openng/icons": "^1.0.0",
"@openng/optimus-ui": "^1.0.1",
"@openng/optimus-ui-tailwindcss": "^1.0.1",
"@openng/optimus-ui-themes": "^1.0.1",
"@tailwindcss/postcss": "^4.3.3",
"marked": "^17.0.6",
"@openng/optimus-ui": "^2.0.1",
"@openng/optimus-ui-tailwindcss": "^2.0.1",
"@openng/optimus-ui-themes": "^2.0.1",
"marked": "^18.0.10",
"rxjs": "~7.8.2",
"tailwindcss": "^4.3.3",
"tslib": "^2.8.1"
},
"devDependencies": {
"@analogjs/vite-plugin-angular": "^2.6.4",
"@analogjs/vitest-angular": "^2.6.4",
"@angular/build": "^21.2.20",
"@angular/cli": "^21.2.20",
"@angular/compiler-cli": "^21.2.19",
"@vitest/coverage-v8": "^4.1.10",
"baseline-browser-mapping": "^2.11.12",
"jsdom": "^26.1.0",
"postcss": "^8.5.25",
"typescript": "~5.9.3",
"vitest": "^4.1.10"
"@analogjs/vite-plugin-angular": "^2.7.0",
"@analogjs/vitest-angular": "^2.7.0",
"@angular/build": "^22.1.5",
"@angular/cli": "^22.1.5",
"@angular/compiler-cli": "^22.1.3",
"@eslint/js": "^10.0.1",
"@tailwindcss/postcss": "^4.3.3",
"@vitest/coverage-v8": "^4.1.11",
"angular-eslint": "^22.1.0",
"baseline-browser-mapping": "^2.11.18",
"eslint": "^10.9.0",
"eslint-plugin-simple-import-sort": "^14.0.0",
"jsdom": "^28.1.0",
"postcss": "^8.5.26",
"prettier": "^3.9.6",
"tailwindcss": "^4.3.3",
"typescript": "~6.0.3",
"typescript-eslint": "^8.67.0",
"vitest": "^4.1.11"
}
}
Loading