Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ea99031
Refactor playground components and improve analytics tracking
nonodev96 Sep 30, 2026
53b8146
feat: update button variant in ModelReviewImageClassification and enh…
nonodev96 Oct 1, 2026
9eb6c32
Add unit tests for TensorFlow backend management and model predictions
nonodev96 Oct 1, 2026
6cb8e62
feat: workers, nuevo AED, más formatos de datos, glosario y mejoras p…
nonodev96 Oct 2, 2026
666c5e3
fix: update DataFrame test dates for consistent timezone handling and…
nonodev96 Oct 2, 2026
3d9ddf3
feat: update GitHub Actions workflows for improved deployment and env…
nonodev96 Oct 2, 2026
406791a
feat: enhance WebGL and system diagnostics, add analysis tab to regre…
nonodev96 Oct 2, 2026
a995aee
feat: guías, configuración, analíticas y 404 animada
nonodev96 Oct 2, 2026
50d2c00
feat(settings): add step-by-step learning option and related settings
nonodev96 Oct 3, 2026
c1b72e2
feat: reset all settings to clear additional user data and improve us…
nonodev96 Oct 3, 2026
e28546e
test: MNIST con una época en e2e
nonodev96 Oct 3, 2026
7de4231
Refactor code style and update types across the project
nonodev96 Oct 4, 2026
a8ec853
feat: add task page and character forms examples for KMNIST
nonodev96 Oct 4, 2026
4e03d02
feat: integrate N4L packages into the application
nonodev96 Oct 5, 2026
072bb51
feat: enhance training timeout configuration for CIFAR-10 and MNIST m…
nonodev96 Oct 5, 2026
3d13066
feat: enhance accessibility tests for loading progress visibility
nonodev96 Oct 5, 2026
091df8e
Add unit tests for object detection, face mesh, hand sign, and time s…
nonodev96 Oct 13, 2026
6dea53d
feat: remove deprecated models and add model management features
nonodev96 Oct 14, 2026
d667ec1
feat: 2D lab, model code view, training prediction and sortable layers
nonodev96 Oct 14, 2026
e23d356
test: longer timeout for the regression page test
nonodev96 Oct 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 0 additions & 3 deletions .env
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
WATCHPACK_POLLING=true
FAST_REFRESH=true
NODE_ENV="development"
PUBLIC_URL="http://localhost:5173/n4l"
VITE_PUBLIC_URL="https://localhost:5173/n4l"
VITE_PATH="/n4l"
VITE_ENVIRONMENT="development"
VITE_GA_MEASUREMENT_ID="G-3644EFBXMG"
VITE_SHOW_NEW_FEATURE="true"
VITE_NEW_FEATURE="linear-regression"
GENERATE_SOURCEMAP=true
3 changes: 0 additions & 3 deletions .env.netlify
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
WATCHPACK_POLLING=true
FAST_REFRESH=true
NODE_ENV="production"
PUBLIC_URL="http://nets4learning.netlify.app"
VITE_PUBLIC_URL="https://nets4learning.netlify.app"
VITE_PATH=""
VITE_ENVIRONMENT="production"
VITE_GA_MEASUREMENT_ID="G-3644EFBXMG"
VITE_SHOW_NEW_FEATURE="true"
VITE_NEW_FEATURE="linear-regression"
GENERATE_SOURCEMAP=true
3 changes: 0 additions & 3 deletions .env.simidat
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
WATCHPACK_POLLING=true
FAST_REFRESH=true
NODE_ENV="production"
PUBLIC_URL="http://simidat.ujaen.es/n4l"
VITE_PUBLIC_URL="https://simidat.ujaen.es/n4l"
VITE_PATH="/n4l"
VITE_ENVIRONMENT="production"
VITE_GA_MEASUREMENT_ID="G-3644EFBXMG"
VITE_SHOW_NEW_FEATURE="true"
VITE_NEW_FEATURE="linear-regression"
GENERATE_SOURCEMAP=true
21 changes: 21 additions & 0 deletions .github/ISSUE_TEMPLATE/accessibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
name: Barrera de accesibilidad / Accessibility barrier
about: Algo que no se puede usar con lector de pantalla, teclado, zoom… / Something you cannot use with a screen reader, keyboard, zoom…
title: '[Accesibilidad] '
labels: 'accesibilidad'
assignees: ''

---

<!-- Gracias por contárnoslo: es la mejor forma de arreglarlo. / Thank you for telling us: it is the best way to fix it. -->

**¿En qué página estabas y qué querías hacer? / Which page were you on and what did you want to do?**


**¿Qué ha pasado? / What happened?**


**Navegador y ayudas técnicas / Browser and assistive technology**
<!-- Por ejemplo: Firefox 140 con NVDA, Safari en iPhone con VoiceOver, solo teclado, zoom al 200 %… -->
<!-- For example: Firefox 140 with NVDA, Safari on iPhone with VoiceOver, keyboard only, 200 % zoom… -->

14 changes: 14 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Qué cambia

<!-- Qué hace este cambio y por qué. -->

## Accesibilidad

<!-- Lo que se comprueba en cada cambio (docs/accessibility.md). Marca lo que hayas revisado o explica por qué no aplica. -->

- [ ] Se puede usar solo con el teclado: se llega a todo, el orden es lógico, el foco se ve y no se pierde.
- [ ] Cada control tiene un nombre que empieza por lo que se ve; las imágenes y las gráficas, su texto alternativo o su tabla («Ver los datos»).
- [ ] Lo que cambia sin mover el foco se anuncia con `announce()`; los errores se dicen junto al campo.
- [ ] Contraste suficiente en los temas claro y oscuro (texto 4,5:1; bordes, iconos y gráficas 3:1) y nada depende solo del color.
- [ ] Se ve bien a 320 px de ancho, con el texto al 200 % y con los ajustes de accesibilidad de /settings.
- [ ] Las páginas o estados nuevos están en las pruebas de axe (`e2e/accesibilidad*.spec.ts`) y, si tienen un flujo nuevo, en `e2e/teclado.spec.ts`.
64 changes: 64 additions & 0 deletions .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: 'Checks'

# Lint, tipos, tests unitarios (vitest) y pruebas en el navegador (Playwright). Se lanzan en cada pull request y,
# antes de publicar, desde deploy.yaml: si algo falla, no se despliega.
on:
pull_request:
workflow_call:

jobs:
static:
name: 'Lint, tipos y tests unitarios'
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v7

# La versión de pnpm se toma de "packageManager" en package.json (pnpm 12, que necesita la 6.1.0 o posterior:
# la etiqueta v6 se quedó en la anterior).
- name: Install pnpm
uses: pnpm/[email protected]

- name: Install Node.js
uses: actions/setup-node@v7
with:
node-version: 24
cache: 'pnpm'

- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm exec tsc -b
- run: pnpm exec vitest run

e2e:
name: 'Pruebas en el navegador (Playwright)'
runs-on: ubuntu-24.04
# Entrenar las tres tareas con WebGL por software lleva unos minutos
timeout-minutes: 30
steps:
- uses: actions/checkout@v7

- name: Install pnpm
uses: pnpm/[email protected]

- name: Install Node.js
uses: actions/setup-node@v7
with:
node-version: 24
cache: 'pnpm'

- run: pnpm install --frozen-lockfile
- run: pnpm exec playwright install --with-deps chromium

# playwright.config.ts construye la versión de Netlify y la sirve con `vite preview`
- run: pnpm test:e2e
env:
NODE_OPTIONS: "--max_old_space_size=6144"

# Informe con capturas y trazas de las pruebas que fallen
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report
retention-days: 14
91 changes: 70 additions & 21 deletions .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,97 @@ on:
push:
tags:
- 'v*'
# Rama de mejoras de la interfaz: se publica en Netlify antes de pasar a main
branches:
- 'mejoras-ui'
# Despliegue manual desde la pestaña Actions
workflow_dispatch:

# Si llegan dos pushes seguidos, solo se publica el último
concurrency:
group: deploy-netlify-stable
cancel-in-progress: true

jobs:
# Lint, tipos, tests unitarios y pruebas en el navegador (checks.yaml): si fallan, no se publica
checks:
name: 'Checks'
uses: ./.github/workflows/checks.yaml

deploy-stable:
name: 'Deploy to netlify stable'
needs: checks
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: 'Create env file'
# Antes de instalar y construir: que el token valga y pueda publicar en el sitio, con un error que diga cuál de
# los dos falla (netlify-cli 17, el de la acción que se usaba antes, decía "Site not found" en ambos casos).
- name: 'Check the Netlify token and site'
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID_STABLE }}
run: |
echo "${{ vars.NETLIFY_ENV_FILE_STABLE }}" > .env.netlify
- uses: actions/checkout@v4
if [ -z "$NETLIFY_AUTH_TOKEN" ] || [ -z "$NETLIFY_SITE_ID" ]; then
echo "::error::Faltan los secretos NETLIFY_AUTH_TOKEN o NETLIFY_SITE_ID_STABLE (Settings › Secrets and variables › Actions)"
exit 1
fi
status() {
curl -sS --retry 2 -o /dev/null -w '%{http_code}' -H "Authorization: Bearer $NETLIFY_AUTH_TOKEN" "https://api.netlify.com/api/v1/$1"
}
user=$(status user)
if [ "$user" != "200" ]; then
echo "::error::Netlify no acepta NETLIFY_AUTH_TOKEN (HTTP $user): ha caducado o se ha revocado. Crea otro en https://app.netlify.com/user/applications#personal-access-tokens y actualiza el secreto"
exit 1
fi
site=$(status "sites/$NETLIFY_SITE_ID")
if [ "$site" != "200" ]; then
echo "::error::El token es válido pero no llega al sitio de NETLIFY_SITE_ID_STABLE (HTTP $site): comprueba el Project ID (Project configuration › General) y que el dueño del token esté en el equipo del sitio"
exit 1
fi
echo "Token y sitio de Netlify correctos"

- uses: actions/checkout@v7
with:
submodules: recursive

# La versión de pnpm se toma de "packageManager" en package.json (pnpm 12).
# Se usa el .env.netlify del repositorio salvo que la variable NETLIFY_ENV_FILE_STABLE traiga otro. Va después
# del checkout: antes, el checkout lo sobrescribía.
- name: 'Create env file'
if: ${{ vars.NETLIFY_ENV_FILE_STABLE != '' }}
env:
ENV_FILE: ${{ vars.NETLIFY_ENV_FILE_STABLE }}
run: printf '%s\n' "$ENV_FILE" > .env.netlify

# La versión de pnpm se toma de "packageManager" en package.json (pnpm 12, que necesita la 6.1.0 o posterior:
# la etiqueta v6 se quedó en la anterior).
- name: Install pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v6.1.0

- name: Install Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v7
with:
node-version: 22
node-version: 24
cache: 'pnpm'

- uses: jsmrcaga/[email protected]
with:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID_STABLE }}
NETLIFY_DEPLOY_MESSAGE: "Deploy v${{ github.ref }}"
NETLIFY_DEPLOY_TO_PROD: true
# NODE_ENV=production (abajo) haría que pnpm omitiera las devDependencies (vite, typescript…)
# que necesita el build: --production=false las instala igualmente.
INSTALL_COMMAND: pnpm install --frozen-lockfile --production=false
BUILD_COMMAND: pnpm run build:netlify
# Vite genera el build en dist/ (no en build/, que era la carpeta de Create React App).
BUILD_DIRECTORY: 'dist'
- run: pnpm install --frozen-lockfile

# Vite genera el build en dist/
- name: Build
run: pnpm run build:netlify
env:
CI: false
NODE_OPTIONS: "--max_old_space_size=6144"
NODE_ENV: "production"
PUBLIC_URL: "https://nets4learning.netlify.app"
VITE_ENVIRONMENT: "production"
VITE_PATH: ""
VITE_PUBLIC_URL: "https://nets4learning.netlify.app"
VITE_GA_MEASUREMENT_ID: "G-3644EFBXMG"
VITE_SHOW_NEW_FEATURE: "false"

# netlify-cli al día (jsmrcaga/action-netlify-deploy, la acción de antes, fijaba la 17, de 2024). Ahora `deploy`
# construye por defecto: --no-build publica el dist/ de arriba.
- name: 'Deploy to Netlify'
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID_STABLE }}
DEPLOY_MESSAGE: "Deploy ${{ github.ref_name }} (${{ github.sha }})"
run: npx --yes netlify-cli@27 deploy --no-build --prod --dir dist --message "$DEPLOY_MESSAGE"
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,10 @@ dist-ssr
*.njsproj
*.sln
*.sw?

# Playwright (pnpm test:e2e)
playwright-report
test-results
blob-report

_tmp/
27 changes: 19 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
</p>

<p align="center">
<a href="https://simidat.ujaen.es/n4l/"><strong>Open the app</strong></a> ·
<a href="https://simidat.ujaen.es/n4l/manual">Manual</a> ·
<a href="https://doi.org/10.3390/electronics13224378">Paper</a> ·
<a href="CHANGELOG.md">Changelog</a> ·
<a href="https://simidat.ujaen.es/n4l/"><strong>Open the app</strong></a> |
<a href="https://simidat.ujaen.es/n4l/manual">Manual</a> |
<a href="https://doi.org/10.3390/electronics13224378">Paper</a> |
<a href="CHANGELOG.md">Changelog</a> |
<a href="LICENSE.md">MIT License</a>
</p>

Expand All @@ -34,7 +34,9 @@ Models*](https://doi.org/10.3390/electronics13224378) (Electronics, 2024). If yo
- **Four tasks:** tabular classification, regression, object detection and image classification.
- **Training in the browser:** layer editor, optimizers, loss functions, metrics and live training charts
(tfjs-vis). You can train several models and compare them.
- **Your own data:** upload a CSV, then clean, encode and scale its columns before training.
- **Your own data:** upload a CSV (comma or semicolon separated, with decimal commas too), ARFF, JSON, JSONL or
Parquet file, then clean, encode and scale its columns before training. Every format is converted to CSV in the
browser and read the same way.
- **Pre-trained models** for each task, ready to try with examples, your own images, a drawing canvas or the webcam.
- **Explainability:** SHAP for tabular data, regression and images, and LRP (layer-wise relevance propagation) for the
handwriting models.
Expand All @@ -61,7 +63,7 @@ React 19, TypeScript 5.9 and Vite 7, with:
- React-Bootstrap for the interface;
- Chart.js and Plotly for charts;
- i18next for translations;
- Vitest and Testing Library for tests.
- Vitest and Testing Library for unit tests, Playwright for browser tests.

## Getting started

Expand All @@ -85,12 +87,15 @@ The app is served at <http://localhost:5173/n4l/>.
| `pnpm preview` | Serve the last build locally |
| `pnpm test` | Run the tests in watch mode (`pnpm test run` runs them once) |
| `pnpm test:ui` / `pnpm test:coverage` | Tests in the Vitest UI / with coverage |
| `pnpm test:e2e` | Browser tests (Playwright, `e2e/`) against the Netlify build |
| `pnpm lint` | ESLint |
| `pnpm version` | Update `CHANGELOG.md` from the commit history |

The build is memory-hungry. If it runs out of memory, run it with
`NODE_OPTIONS="--max-old-space-size=8192"`, as the Docker image does.

The first time you run `pnpm test:e2e`, install its browser with `pnpm exec playwright install chromium`.

### Environment variables

Vite reads `.env` and then `.env.<mode>`. The three files are versioned:
Expand All @@ -106,10 +111,15 @@ The app uses these variables:
| `VITE_PATH` | Path the app is served under: `"/n4l"` or `""` for the domain root. It also sets Vite's `base`. |
| `VITE_ENVIRONMENT` | `development` enables i18next debug logs, shorter default training and development panels. Any value other than `production` also enables the development-only pages, `/debug` and the test pages. |
| `VITE_GA_MEASUREMENT_ID` | Google Analytics 4 measurement ID. |
| `VITE_SHOW_NEW_FEATURE` | `"true"` shows sections that are still in progress (glossary, datasets page). |

## Deployment

### Netlify

[`deploy.yaml`](.github/workflows/deploy.yaml) publishes to Netlify on every `v*` tag (and on pushes to the
`mejoras-ui` branch). It first runs [`checks.yaml`](.github/workflows/checks.yaml) (lint, types, unit tests and
browser tests), the same checks every pull request gets: if any of them fails, nothing is published.

### Docker

The [Dockerfile](Dockerfile) builds the app with pnpm and serves it with an unprivileged nginx under `/n4l/`. It uses
Expand All @@ -136,6 +146,7 @@ src/
MODEL_KEYS.ts Dataset and model identifiers
Scripts/ Dataset and model generation
tests/ Vitest tests
e2e/ Playwright tests
```

To add a dataset or a pre-trained model:
Expand All @@ -148,7 +159,7 @@ To add a dataset or a pre-trained model:

- Commits follow [Conventional Commits](https://www.conventionalcommits.org/); commitlint checks them.
- Before opening a pull request, run `pnpm lint`, `pnpm test run` and `pnpm build:simidat`. The build also
type-checks the project.
type-checks the project. CI also runs `pnpm test:e2e`.
- New interface texts go into the three translation files. Manual pages go into `public/docs/{en,es,ja}`.

## Team
Expand Down
Binary file not shown.
Loading
Loading