Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
8b76b48
docs: add Vue 2→3 / Nuxt 2→4 migration design
JonnyTran Jun 13, 2026
6d9682f
docs: add Vue 2→3 / Nuxt 2→4 implementation plan
JonnyTran Jun 13, 2026
c54236f
chore: gitignore .worktree/ for isolated worktrees
JonnyTran Jun 13, 2026
c97c417
build: swap dependency set for Vue 3 / Nuxt 4
JonnyTran Jun 13, 2026
826c651
config: port nuxt.config to Nuxt 4 (vite, nitro proxy, i18n v10)
JonnyTran Jun 13, 2026
0343a5e
config: drop babel/jest config, extend Nuxt 4 tsconfig
JonnyTran Jun 13, 2026
b9d9726
test: add Vitest + @nuxt/test-utils config and setup
JonnyTran Jun 13, 2026
1efbe0d
refactor: replace Vue.filter number formatters with helpers
JonnyTran Jun 13, 2026
3dea37a
refactor: replace Vue-instance toast bus with mitt
JonnyTran Jun 13, 2026
ab9d482
refactor: port tooltip directive to Vue 3 createApp
JonnyTran Jun 13, 2026
fda710a
refactor: reimplement v-click-outside via @vueuse/core
JonnyTran Jun 13, 2026
4605253
feat: custom svg-icon component replacing vue-svgicon
JonnyTran Jun 13, 2026
5a6a120
refactor: Nuxt 4 plugin + global middleware structure
JonnyTran Jun 13, 2026
a1b1463
feat: plain-axios HTTP plugin with ported error handler + cache
JonnyTran Jun 13, 2026
cbffef2
feat: custom AuthService token store implementing IAuthService
JonnyTran Jun 13, 2026
7d101ba
refactor: migrate composition-api imports to Vue 3 / Nuxt composables
JonnyTran Jun 13, 2026
b929dc0
refactor: Vue 3 template + Options-API codemods (.vue)
JonnyTran Jun 13, 2026
6c69102
refactor: replace $root/$nuxt bus, $nuxt.$t, $destroy (Vue 3 removals)
JonnyTran Jun 13, 2026
d188f21
refactor: port draggable, tiptap, md-loader to Vue 3 / Nuxt 4
JonnyTran Jun 13, 2026
f837a30
fix(build): i18n strictMessage, static assets, v-click-outside/vue-de…
JonnyTran Jun 13, 2026
aad4476
fix(build): i18n entry import, pdf-viewer v-model-on-prop, template v…
JonnyTran Jun 13, 2026
808de91
build: pin all @intlify/* runtime packages to 11.4.5, drop Vue-2 pdf-…
JonnyTran Jun 13, 2026
55ec7a2
fix(build): Vue 3 createApp span-entity factory, dompurify default im…
JonnyTran Jun 13, 2026
3ec7033
fix(vue3): mark type-only imports with inline `type` modifier (216 ac…
JonnyTran Jun 13, 2026
996dee8
test(vitest): mechanical jest->vi, propsData->props, destroy->unmount…
JonnyTran Jun 13, 2026
6da3a25
test: port unit suite to Vitest + VTU v2 (735 passing, >= baseline pa…
JonnyTran Jun 13, 2026
fff7f97
config: ESLint 8 flat-compat fix + preserve non-strict TS posture (Nu…
JonnyTran Jun 13, 2026
041331b
docs: update frontend CLAUDE.md for Vue 3 / Nuxt 4 / Vitest stack
JonnyTran Jun 13, 2026
654080c
fix(vue3): drive nuxi typecheck to 0; fix runtime bugs surfaced by ty…
JonnyTran Jun 13, 2026
777935c
chore: update .gitignore and docker-compose for service profiles
JonnyTran Jun 13, 2026
52e5b8a
docs: vue3 remediation plan (session 4)
JonnyTran Jun 13, 2026
35e15c9
test(vue3): snapshot HTML not VueWrapper in base-date; drop leaked-pa…
JonnyTran Jun 13, 2026
56a2c8f
fix(vue3): migrate dynamic routes to bracket form + revive page guards
JonnyTran Jun 13, 2026
aa51931
fix(vue3): unmount span entity Vue apps to stop leak
JonnyTran Jun 13, 2026
c4c3279
fix(vue3): useHead() for page title + wire root error.vue
JonnyTran Jun 13, 2026
ab9de1b
fix(vue3): rename transition start-state classes to *-enter-from
JonnyTran Jun 13, 2026
e970473
fix(vue3): inject highlight CSS as <style> text child, not v-html
JonnyTran Jun 13, 2026
ce3b87d
fix(vue3): replace removed $slots.default VNode API
JonnyTran Jun 13, 2026
65d68d4
fix(vue3): correct $attrs listener-detection key (on-click -> onOnClick)
JonnyTran Jun 13, 2026
9831e86
chore(vue3): restore working ESLint config + config cleanups
JonnyTran Jun 13, 2026
1ed8813
fix(vue3): declare emits on native-event-emitting components
JonnyTran Jun 13, 2026
c00df30
docs(vue3): record rationale for pages:extend filter and eslint globals
JonnyTran Jun 13, 2026
5661891
fix(vue3): repair v-model on LoginInput so sign-in works again
JonnyTran Jun 13, 2026
22fa099
fix(vue3): migrate all components off the removed Vue 2 `model:` option
JonnyTran Jun 13, 2026
ed37539
docs(vue3): record reconciled e2e login helper in CLAUDE.md
JonnyTran Jun 14, 2026
abcc6f3
fix(vue3): preserve /api prefix in nitro devProxy
JonnyTran Jun 14, 2026
9a84793
fix(vue3): pass primitive string to $t for Field/Question type badges
JonnyTran Jun 14, 2026
1a65e34
fix(vue3): make BaseInput dual-purpose so v-model binds
JonnyTran Jun 14, 2026
f4c2eb6
fix: update ImportFlow.spec.js to improve component stubbing and add …
JonnyTran Jun 17, 2026
b28c12b
chore: update subproject commit and add @vitest/coverage-v8 dependency
JonnyTran Jun 17, 2026
a188aee
Merge branch 'develop' into feat/vue-v2-to-v3
JonnyTran Jun 18, 2026
457a5b3
Merge branch 'develop' into feat/vue-v2-to-v3
JonnyTran Jun 18, 2026
ba2ecb6
Merge branch 'develop' into feat/vue-v2-to-v3
JonnyTran Jun 18, 2026
f6aa7ad
fix(ci): serve Nuxt 4 SPA + restore frontend lint/test in CI
JonnyTran Jun 18, 2026
0a4897b
fix(frontend): stop welcome-hf-sign-in redirect loop on Vue Router 4
JonnyTran Jun 18, 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
  •  
  •  
  •  
13 changes: 8 additions & 5 deletions .github/workflows/extralit-frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,20 @@ jobs:

- name: Build package 📦
env:
# BASE_URL is used in the server to support parameterizable base root path
BASE_URL: "@@baseUrl@@"
DIST_FOLDER: ./dist
# Nuxt 4 SPA (ssr:false) ships as static files served at the site root, so build at
# base "/". (The Nuxt 2 "@@baseUrl@@" placeholder breaks Nuxt 4's prerender crawler;
# parameterizable sub-path hosting is a separate follow-up.)
BASE_URL: "/"
run: |
npm run build
# `nuxi generate` prerenders the SPA shell to .output/public (index.html + _nuxt
# assets); `nuxi build` only emits a Nitro server with no static index.html.
npm run generate

- name: Upload frontend statics as artifact
uses: actions/upload-artifact@v4
with:
name: extralit-frontend
path: extralit-frontend/dist
path: extralit-frontend/.output/public

# build_dev_docker_image:
# name: Build development extralit-frontend docker image
Expand Down
17 changes: 13 additions & 4 deletions .github/workflows/extralit-pr-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,24 @@ jobs:
- name: Install frontend dependencies
working-directory: extralit-frontend
env:
BASE_URL: "@@baseUrl@@"
DIST_FOLDER: ./dist
# Nuxt 4 SPA (ssr:false) is served as static files from the server's static dir at
# the site root, so build at base "/". (The Nuxt 2 "@@baseUrl@@" placeholder, which
# the server rewrote at runtime, breaks Nuxt 4's prerender crawler and yields "//_nuxt"
# asset paths; parameterizable sub-path hosting is a separate follow-up.)
BASE_URL: "/"
run: |
npm install
npm run build
# `nuxi generate` prerenders the SPA shell to .output/public (index.html + _nuxt
# assets); `nuxi build` only emits a Nitro server with no static index.html.
npm run generate

- name: Build package
run: |
cp -r ../extralit-frontend/dist src/extralit_server/static
set -euo pipefail
# Bake the compiled SPA into the wheel's static dir. Fail loudly if it's missing or
# empty, otherwise the server ships with no statics and 404s every route.
cp -r ../extralit-frontend/.output/public src/extralit_server/static
test -f src/extralit_server/static/index.html
uv build

- name: Upload artifact
Expand Down
17 changes: 13 additions & 4 deletions .github/workflows/extralit-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,24 @@ jobs:
- name: Install frontend dependencies
working-directory: extralit-frontend
env:
BASE_URL: "@@baseUrl@@"
DIST_FOLDER: ./dist
# Nuxt 4 SPA (ssr:false) is served as static files from the server's static dir at
# the site root, so build at base "/". (The Nuxt 2 "@@baseUrl@@" placeholder, which
# the server rewrote at runtime, breaks Nuxt 4's prerender crawler and yields "//_nuxt"
# asset paths; parameterizable sub-path hosting is a separate follow-up.)
BASE_URL: "/"
run: |
npm install
npm run build
# `nuxi generate` prerenders the SPA shell to .output/public (index.html + _nuxt
# assets); `nuxi build` only emits a Nitro server with no static index.html.
npm run generate
# End of frontend build section
- name: Build package
run: |
cp -r ../extralit-frontend/dist src/extralit_server/static
set -euo pipefail
# Bake the compiled SPA into the wheel's static dir. Fail loudly if it's missing or
# empty, otherwise the server ships with no statics and 404s every route.
cp -r ../extralit-frontend/.output/public src/extralit_server/static
test -f src/extralit_server/static/index.html
uv build

- name: Upload artifact
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,4 @@ output/

**/.playwright-mcp/
**/.nuxt-stale-root/
.worktree/
.worktree/
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Architecture Notes
- **extralit-server/**: FastAPI + PostgreSQL + Redis Queue
- **extralit-frontend/**: Vue.js/Nuxt.js (Vuex → Pinia migration)
- **extralit-frontend/**: Vue 3 / Nuxt 4 (Vite); Pinia state management
- **extralit/**: Python SDK client
- **extralit-hf-space/**: Self-contained HF Spaces deployment bundle (Docker; bundles Elasticsearch + Redis + OCR) — git submodule
- **Vector DB**: Elasticsearch/OpenSearch (separate service)
Expand Down
35 changes: 31 additions & 4 deletions extralit-frontend/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ module.exports = {
"plugin:@intlify/vue-i18n/recommended",
"plugin:prettier/recommended",
"plugin:nuxt/recommended",
"prettier/vue",
],
plugins: ["vue"],
settings: {
"vue-i18n": {
localeDir: "./translation/*.json",
localeDir: "./translation/*.js",
},
},
rules: {
// Formatting is advisory here (parity with the *.ts override and the separate
// `npm run format` step); keeps `lint --quiet` focused on real correctness rules.
"prettier/prettier": "warn",
"no-console": process.env.NODE_ENV === "production" ? "error" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
"prefer-const": "warn",
Expand Down Expand Up @@ -48,14 +51,38 @@ module.exports = {
},
globals: {
$nuxt: true,
vi: true,
// Nuxt 4 auto-imports, hand-declared to satisfy no-undef. This list can drift;
// the real fix is adopting `@nuxt/eslint` (flat config), which auto-generates
// these globals from the build manifest. Tracked as follow-up, not done here.
defineNuxtPlugin: "readonly",
defineNuxtRouteMiddleware: "readonly",
definePageMeta: "readonly",
navigateTo: "readonly",
abortNavigation: "readonly",
useNuxtApp: "readonly",
useRuntimeConfig: "readonly",
useRoute: "readonly",
useRouter: "readonly",
useState: "readonly",
useCookie: "readonly",
useHead: "readonly",
useSeoMeta: "readonly",
useError: "readonly",
createError: "readonly",
clearError: "readonly",
showError: "readonly",
},
parser: "vue-eslint-parser",
parserOptions: {
parser: "@babel/eslint-parser",
parser: "@typescript-eslint/parser",
ecmaVersion: 2022,
sourceType: "module",
},
overrides: [
{
files: ["**/*.ts"],
extends: ["@nuxtjs/eslint-config-typescript", "prettier"],
extends: ["plugin:@typescript-eslint/recommended", "prettier"],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint", "prettier"],
parserOptions: { project: ["./tsconfig.json"] },
Expand Down
6 changes: 6 additions & 0 deletions extralit-frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
.nuxtrc
.nuxt/
.output/
.nitro/
.cache/
dist/
50 changes: 39 additions & 11 deletions extralit-frontend/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ API_BASE_URL=https://extralit-public-demo.hf.space/ npm run dev
## Testing

```bash
npm run test # Jest unit tests
npm run test # Vitest unit tests (run once)
npm run test:watch # Watch mode
npm run test:coverage # With coverage

Expand All @@ -34,35 +34,63 @@ npm run e2e:silent # Playwright headless
npm run e2e:report # View test report
```

> Unit tests run on **Vitest** (`vitest.config.ts` + `test/setup.ts`), using
> `@vue/test-utils` v2 and `@nuxt/test-utils`. Specs needing Nuxt runtime context use
> `// @vitest-environment nuxt` or `mockNuxtImport`.
>
> The Playwright e2e suite is inherited from upstream Argilla. The shared login helper
> (`e2e/common/login-and-wait-for.ts`) has been reconciled to Extralit's real sign-in UI:
> it fills `getByLabel("Username"/"Password")`, submits the `"Sign in"` button, mocks
> `/api/v1/token` + `/api/v1/me` offline, and waits for the home/datasets landing at `/`
> (there is no `/datasets` route). This flow is runtime-verified via the CDP browser. The
> per-page specs still need fresh Extralit screenshot baselines (`--update-snapshots`); the
> inherited ones are Argilla's. The local Playwright browser can't launch on the Orin dev
> host (missing OS libs, no sudo) — run the headless gate in CI.

## Code Quality

```bash
npm run lint # ESLint check
npm run lint # ESLint check (eslint 8 + vue-eslint-parser)
npm run lint:fix # Fix ESLint issues
npm run format # Format with Prettier
npm run format:check # Check formatting
npm run generate-icons # Generate icon components from SVG

npx nuxi typecheck # vue-tsc type check
npm run build # Production build (vite/nitro)
```

## Requirements

- Node.js 18+
- Node.js 18+ (developed on Node 24)
- Backend server running for full functionality

## Architecture

**Migration in progress**: Vuex → Pinia

- **v1/** directory: New Pinia architecture with domain-driven design
- Domain-driven design with entities, use cases, dependency injection
- **v1/** directory: Pinia + domain-driven design (entities, use cases, dependency injection
via `ts-injecty`). The domain/use-case layer is framework-agnostic; only the Vue/Nuxt
adapters (HTTP, Auth, Icons) were swapped during the Vue 3 / Nuxt 4 migration.
- Component hierarchy: base (stateless) → features (page-specific) → global (reusable)
- HTTP: plain `axios` in `plugins/2.axios.ts` (replaced `@nuxtjs/axios`), re-injected into DI.
- Auth: `AuthService` (`v1/infrastructure/services/AuthService.ts`) implementing `IAuthService`,
provided as `$auth` by `plugins/1.auth.ts` (replaced `@nuxtjs/auth-next`).
- Icons: custom `<svg-icon>` (`components/base/BaseSvgIcon.vue`) reading `static/icons/*.svg`
(replaced `vue-svgicon`).
- Plugins load in order via numeric prefixes (`1.auth` → `2.axios` → `3.di`); middleware are
Nuxt-4 globals (`middleware/*.global.ts`).

> **TS posture:** `tsconfig.json` keeps `strict:false` (matching the pre-Vue3 config) and
> disables Nuxt-4's new `verbatimModuleSyntax`/`noImplicitOverride`. Tightening to strict is a
> separate hardening effort. Note: Vite/esbuild (`isolatedModules`) requires type-only imports
> to use the inline `import { type X }` modifier or they throw at runtime in dev.

## Key Technologies

- Vue.js + Nuxt.js
- Pinia (state management, replacing Vuex)
- Jest (unit tests) + Playwright (e2e)
- ESLint + Prettier
- Vue 3.5 + Nuxt 4 (Vite + Nitro)
- Pinia (state management; Vuex fully removed)
- Vitest + @vue/test-utils v2 (unit) + Playwright (e2e)
- @nuxtjs/i18n v10 (vue-i18n v11), @vueuse/core, mitt
- ESLint 8 + Prettier

## Structure

Expand Down
1 change: 1 addition & 0 deletions extralit-frontend/__mocks__/empty.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* test stub */
10 changes: 0 additions & 10 deletions extralit-frontend/assets/icon-template.js.tmp

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/arrow-down.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/arrow-up.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/assign.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/bulk-mode.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/change-height.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/check.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/chevron-down.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/chevron-left.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/chevron-right.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/chevron-up.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/clear.js

This file was deleted.

10 changes: 0 additions & 10 deletions extralit-frontend/assets/icons/close.js

This file was deleted.

Loading
Loading